fixed a bug on new project creation where the config file path wasn't

being passed correctly. Also started the groundwork for adding more of
my rust based tooling to tetanus.
This commit is contained in:
2026-08-27 12:23:18 -05:00
parent 9ed69b03a0
commit 0bb3a125aa
6 changed files with 1469 additions and 167 deletions
Generated
+583 -15
View File
@@ -2,6 +2,12 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]] [[package]]
name = "aead" name = "aead"
version = "0.6.1" version = "0.6.1"
@@ -329,6 +335,20 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "auto_generate_cdp"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "359220d0b9360b79d17d648d0a3ba1e792ec36bdbc227c8fd0351df3a0415704"
dependencies = [
"convert_case 0.8.0",
"proc-macro2",
"quote",
"serde",
"serde_json",
"ureq",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.1" version = "1.5.1"
@@ -364,6 +384,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.5.3" version = "0.5.3"
@@ -670,6 +696,15 @@ dependencies = [
"tiny-keccak", "tiny-keccak",
] ]
[[package]]
name = "convert_case"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.10.0" version = "0.10.0"
@@ -719,6 +754,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc32fast"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.6" version = "0.8.6"
@@ -826,14 +870,38 @@ dependencies = [
"cmov", "cmov",
] ]
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core 0.20.11",
"darling_macro 0.20.11",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.23.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.23.0",
"darling_macro", "darling_macro 0.23.0",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.117",
] ]
[[package]] [[package]]
@@ -849,13 +917,24 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
"syn 2.0.117",
]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.23.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.23.0",
"quote", "quote",
"syn 2.0.117", "syn 2.0.117",
] ]
@@ -895,6 +974,37 @@ dependencies = [
"powerfmt", "powerfmt",
] ]
[[package]]
name = "derive_builder"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
"darling 0.20.11",
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.117",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "2.1.1" version = "2.1.1"
@@ -910,7 +1020,7 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
dependencies = [ dependencies = [
"convert_case", "convert_case 0.10.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustc_version", "rustc_version",
@@ -1088,6 +1198,16 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -1100,6 +1220,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]] [[package]]
name = "fs_extra" name = "fs_extra"
version = "1.3.0" version = "1.3.0"
@@ -1232,6 +1361,29 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "headless_chrome"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5754ca220578ad74a5d5174c8ca2ff956fd3b94025f870844de1e910b47dfee5"
dependencies = [
"anyhow",
"auto_generate_cdp",
"base64 0.22.1",
"derive_builder",
"log",
"rand 0.10.2",
"regex",
"serde",
"serde_json",
"tempfile",
"thiserror 2.0.18",
"tungstenite",
"url",
"which",
"winreg",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@@ -1268,6 +1420,22 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "http"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0"
dependencies = [
"bytes",
"itoa",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]] [[package]]
name = "hybrid-array" name = "hybrid-array"
version = "0.4.14" version = "0.4.14"
@@ -1277,12 +1445,116 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "icu_collections"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
[[package]]
name = "icu_properties"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa"
[[package]]
name = "icu_provider"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" 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 = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.14.0" version = "2.14.0"
@@ -1327,7 +1599,7 @@ version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971"
dependencies = [ dependencies = [
"darling", "darling 0.23.0",
"indoc", "indoc",
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1448,6 +1720,12 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
[[package]] [[package]]
name = "litrs" name = "litrs"
version = "1.0.0" version = "1.0.0"
@@ -1465,9 +1743,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.31" version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]] [[package]]
name = "lru" name = "lru"
@@ -1524,6 +1802,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.2.1" version = "1.2.1"
@@ -1839,10 +2127,16 @@ version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
dependencies = [ dependencies = [
"base64", "base64 0.22.1",
"serde_core", "serde_core",
] ]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.8.6" version = "2.8.6"
@@ -1992,12 +2286,30 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
[[package]]
name = "potential_utf"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"
dependencies = [
"zerovec",
]
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "3.5.0" version = "3.5.0"
@@ -2046,6 +2358,16 @@ dependencies = [
"rand_core 0.6.4", "rand_core 0.6.4",
] ]
[[package]]
name = "rand"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
dependencies = [
"rand_chacha",
"rand_core 0.9.5",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.10.2" version = "0.10.2"
@@ -2057,12 +2379,31 @@ dependencies = [
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.5",
]
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.6.4" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.10.1" version = "0.10.1"
@@ -2199,9 +2540,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.12.3" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -2211,9 +2552,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.14" version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -2222,9 +2563,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.10" version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]] [[package]]
name = "rhai" name = "rhai"
@@ -2317,6 +2658,7 @@ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"log", "log",
"once_cell", "once_cell",
"ring",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki", "rustls-webpki",
"subtle", "subtle",
@@ -2482,6 +2824,17 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "sha1"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8"
dependencies = [
"cfg-if",
"cpufeatures 0.2.17",
"digest",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.9" version = "0.10.9"
@@ -2530,6 +2883,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "simd-adler32"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
[[package]] [[package]]
name = "siphasher" name = "siphasher"
version = "1.0.3" version = "1.0.3"
@@ -2579,12 +2938,29 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "socks"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
dependencies = [
"byteorder",
"libc",
"winapi",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@@ -2724,7 +3100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64 0.22.1",
"bitflags 2.12.1", "bitflags 2.12.1",
"fancy-regex", "fancy-regex",
"filedescriptor", "filedescriptor",
@@ -2769,6 +3145,7 @@ dependencies = [
"clipboard", "clipboard",
"crossterm", "crossterm",
"fs_extra", "fs_extra",
"headless_chrome",
"ipnet", "ipnet",
"keyring", "keyring",
"rand 0.10.2", "rand 0.10.2",
@@ -2888,6 +3265,16 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "tinystr"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.52.3" version = "1.52.3"
@@ -2987,6 +3374,22 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tungstenite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
dependencies = [
"bytes",
"data-encoding",
"http",
"httparse",
"log",
"rand 0.9.5",
"sha1",
"thiserror 2.0.18",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.20.1" version = "1.20.1"
@@ -3061,6 +3464,60 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d"
dependencies = [
"base64 0.23.1",
"flate2",
"log",
"percent-encoding",
"rustls",
"rustls-pki-types",
"socks",
"ureq-proto",
"utf8-zero",
"webpki-roots",
]
[[package]]
name = "ureq-proto"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da5f78b09e6941e1a0f2e30e695e4b120377b54d5e0aec11b594bb57b3971613"
dependencies = [
"base64 0.23.1",
"http",
"httparse",
"log",
]
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "utf8-zero"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e"
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@@ -3175,6 +3632,15 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webpki-roots"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a"
dependencies = [
"rustls-pki-types",
]
[[package]] [[package]]
name = "wezterm-bidi" name = "wezterm-bidi"
version = "0.2.3" version = "0.2.3"
@@ -3247,6 +3713,15 @@ dependencies = [
"wezterm-dynamic", "wezterm-dynamic",
] ]
[[package]]
name = "which"
version = "8.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -3492,12 +3967,28 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
dependencies = [
"cfg-if",
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.57.1" version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "writeable"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]] [[package]]
name = "x11-clipboard" name = "x11-clipboard"
version = "0.3.3" version = "0.3.3"
@@ -3545,6 +4036,29 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "yoke"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"synstructure",
]
[[package]] [[package]]
name = "zbus" name = "zbus"
version = "5.16.0" version = "5.16.0"
@@ -3637,12 +4151,66 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "zerofrom"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"synstructure",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.9.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
[[package]]
name = "zerotrie"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]] [[package]]
name = "zmij" name = "zmij"
version = "1.0.21" version = "1.0.21"
+1
View File
@@ -10,6 +10,7 @@ clap = { version = "4.6.1", features = ["derive"] }
clipboard = "0.5.0" clipboard = "0.5.0"
crossterm = "0.29.0" crossterm = "0.29.0"
fs_extra = "1.3.0" fs_extra = "1.3.0"
headless_chrome = "1.0.22"
ipnet = "2.12.0" ipnet = "2.12.0"
keyring = "4.1.6" keyring = "4.1.6"
rand = "0.10.2" rand = "0.10.2"
+55 -3
View File
@@ -49,6 +49,7 @@ pub fn startup(
let response = get_user_input("which config would you like to load?")?; let response = get_user_input("which config would you like to load?")?;
if let Some(path) = selections.get(&response) { if let Some(path) = selections.get(&response) {
app.load_config(PathBuf::from(path), true)?; app.load_config(PathBuf::from(path), true)?;
println!("entering tui...");
run_tui(app, rx, handles.clone())?; run_tui(app, rx, handles.clone())?;
} else { } else {
eprintln!("error invalid selection! exiting..."); eprintln!("error invalid selection! exiting...");
@@ -56,11 +57,13 @@ pub fn startup(
} }
} else { } else {
app.load_config(state.config_file.clone(), true)?; app.load_config(state.config_file.clone(), true)?;
println!("entering tui...");
run_tui(app, rx, handles.clone())?; run_tui(app, rx, handles.clone())?;
} }
if nested { if nested {
let (tx, rx) = channel(); let (tx, rx) = channel();
state.main_tx = tx; state.main_tx = tx;
println!("returning to prevous tui...");
run_tui(state, rx, handles.clone())?; run_tui(state, rx, handles.clone())?;
} }
Ok(()) Ok(())
@@ -475,6 +478,35 @@ pub fn run_tui(
); );
} }
"CMD" => { "CMD" => {
if let Some((cmd, data)) =
data.split_once("|")
{
match cmd.trim() {
"SET_NAME" => {
locked_server
.name = data
.trim()
.to_string();
}
"LIST_PROJECTS" => {
let _ = ToolMessage::Input((locked_server.client_id.clone(), "list_projects".to_string()));
}
_ => {
let msg = format!(
"MSG FROM: {}",
data.trim()
);
let _ = tx_clone.send(
ToolMessage::Output((
locked_server
.client_id
.clone(),
msg,
)),
);
}
}
}
if data.contains("SET_NAME") { if data.contains("SET_NAME") {
if let Some((_, name)) = if let Some((_, name)) =
data.split_once("|") data.split_once("|")
@@ -485,7 +517,7 @@ pub fn run_tui(
} }
} else { } else {
let _ = tx_clone.send( let _ = tx_clone.send(
ToolMessage::Input(( ToolMessage::Output((
locked_server locked_server
.client_id .client_id
.clone(), .clone(),
@@ -680,18 +712,38 @@ pub fn run_tui(
} }
} else { } else {
if args == "" { if args == "" {
let _ = state.execute_command(command, None, 0); match state.execute_command(command, None, 0) {
Ok(_) => {}
Err(e) => {
let _ = state.main_tx.send(
ToolMessage::Output((
0,
e.to_string(),
)),
);
}
}
} else { } else {
let _ = state.execute_command( match state.execute_command(
command, command,
Some(args.to_string()), Some(args.to_string()),
0, 0,
) {
Ok(_) => {}
Err(e) => {
let _ = state.main_tx.send(
ToolMessage::Output((
0,
e.to_string(),
)),
); );
} }
} }
} }
} }
} }
}
}
state.curent_intput.clear(); state.curent_intput.clear();
} }
history_index = state.history.len(); history_index = state.history.len();
+642 -94
View File
@@ -14,13 +14,17 @@ use std::io::{self, BufRead, BufReader, Read, Write};
use std::net::IpAddr; use std::net::IpAddr;
use std::net::TcpStream; use std::net::TcpStream;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{Command, CommandArgs, Stdio}; use std::process::{Command, Stdio};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex, mpsc::Sender, mpsc::channel}; use std::sync::{Arc, Mutex, mpsc::Sender, mpsc::channel};
use std::time::Duration; use std::time::Duration;
use std::time::{self, Instant}; use std::time::{self, Instant};
use walkdir::WalkDir;
use crate::rust_tools::rustwitness;
pub mod funcs; pub mod funcs;
pub mod rust_tools;
pub mod server; pub mod server;
pub mod victim; pub mod victim;
@@ -242,6 +246,10 @@ impl AppState {
.to_string(), .to_string(),
); );
self.help.push("parse_scope\nparse the projects general.md notes file for the scope copied from the workbook\n".to_string()); self.help.push("parse_scope\nparse the projects general.md notes file for the scope copied from the workbook\n".to_string());
self.help.push("parse_portscan | pps\nParse a services.tsv file exported from cobalt stirke in your current project's files directory".to_string());
self.help
.push("stop_db\nrestart this project's distrobox".to_string());
self.help.push("rustwitness\nRun a scan on the hosts in the urls.txt file in yoru project files directory that captures screenshots of those urls, optionally through a proxy.".to_string());
self.help.push("exit\nquit the tool\n".to_string()); self.help.push("exit\nquit the tool\n".to_string());
self.initialize_modules(); self.initialize_modules();
return Ok(()); return Ok(());
@@ -392,6 +400,10 @@ impl AppState {
} else { } else {
out_vec.push(format!("status: upcoming")); out_vec.push(format!("status: upcoming"));
} }
out_vec.push(format!(
"Num hosts: {}",
&self.projects[self.selected_project].hosts.iter().count()
));
for line in out_vec { for line in out_vec {
let _ = self.main_tx.send(ToolMessage::Output((rid, line))); let _ = self.main_tx.send(ToolMessage::Output((rid, line)));
} }
@@ -438,7 +450,7 @@ impl AppState {
let project = self.projects[self.selected_project].clone(); let project = self.projects[self.selected_project].clone();
let mut config_file = project.config_folder.clone(); let mut config_file = project.config_folder.clone();
config_file.pop(); config_file.pop();
if let Err(e) = remove_dir_all(&project.config_folder) { if let Err(e) = remove_dir_all(config_file) {
let _ = self.main_tx.send(ToolMessage::Output(( let _ = self.main_tx.send(ToolMessage::Output((
rid, rid,
format!( format!(
@@ -947,6 +959,75 @@ impl AppState {
}); });
} }
} }
"collab_with" => {
if let Some(args) = command_args {
if let Ok(id) = args.trim().parse::<usize>() {
if let Some(server) = self.servers.get(self.selected_server) {
if let Ok(mut lock) = server.lock() {
lock.action_que.push(format!("COLLAB|{}", id));
}
}
}
}
}
"collab" => {
if let Some(args) = command_args {
if let Some(server) = self.servers.get(self.selected_server) {
if let Ok(mut lock) = server.lock() {
lock.action_que.push(format!("CMD|{}", args));
}
}
}
}
"parse_port_scan" | "pps" => {
self.parse_cs_portscan()?;
}
"stop_db" => {
if let Some(project) = self.projects.get_mut(self.selected_project) {
if let Some(db) = project.db.as_mut() {
db.stop(self.main_tx.clone(), rid)?;
}
}
}
"rustwitness" => {
if let Some(project) = self.projects.get(self.selected_project) {
if let Some(args) = command_args {
if let Some((outfile, proxy)) = args.split_once(" ") {
let mut proxy_string = None;
if let Some((ip, port)) = proxy.split_once(" ") {
proxy_string = Some(format!("socks5://{}:{}", ip, port));
}
WalkDir::new(&project.files)
.into_iter()
.filter(|res| res.is_ok())
.for_each(|res| {
if let Ok(entry) = res {
if entry.file_name().to_string_lossy().contains("urls.txt")
{
let input = PathBuf::from(entry.path());
let mut output = project.files.clone();
output.push(outfile.trim());
let proxy_intput = proxy_string.clone();
let tx = self.main_tx.clone();
self.workers.spawn(move || {
rustwitness(input, output, proxy_intput, tx)
});
}
}
});
}
} else {
let _ = self.main_tx.send(ToolMessage::Output((
0,
"[error] incorrect command usage!".to_string(),
)));
let _ = self.main_tx.send(ToolMessage::Output((
0,
"usage: rustwitness output_file_name optional_proxy_ip optional_proxy_port".to_string(),
)));
}
}
}
"exit" => { "exit" => {
self.save_all()?; self.save_all()?;
let _ = self.main_tx.send(ToolMessage::AppStateExit); let _ = self.main_tx.send(ToolMessage::AppStateExit);
@@ -966,7 +1047,7 @@ impl AppState {
.module_loader .module_loader
.asts .asts
.get(command_name) .get(command_name)
.ok_or_else(|| format!("Command not found: {}", command_name))? .ok_or_else(|| format!("[error] Command not found: {}", command_name))?
.clone(); .clone();
let engine = Arc::clone(&self.module_loader.engine); let engine = Arc::clone(&self.module_loader.engine);
let cmd_meta = self let cmd_meta = self
@@ -1001,12 +1082,28 @@ impl AppState {
} }
scope.push("config", map); scope.push("config", map);
} }
"distrobox" => {
if let Some(db) = self.projects[self.selected_project].db.clone() {
scope.push("distrobox", db);
}
}
_ if arg_requirement.starts_with("string") => { _ if arg_requirement.starts_with("string") => {
let input_val = command_args let input_val = command_args
.clone() .clone()
.unwrap_or_else(|| self.curent_intput.clone()); .unwrap_or_else(|| self.curent_intput.clone());
scope.push("input_string", input_val); scope.push("input_string", input_val);
} }
_ if arg_requirement.starts_with("bool") => {
let mut input_val = false;
if command_args
.clone()
.unwrap_or_else(|| self.curent_intput.clone())
.contains("true")
{
input_val = true;
}
scope.push("input_bool", input_val);
}
_ => {} _ => {}
} }
} }
@@ -1053,7 +1150,7 @@ impl AppState {
Err(err) => { Err(err) => {
let _ = tx.send(ToolMessage::Output(( let _ = tx.send(ToolMessage::Output((
rid, rid,
format!("Script [error] in execution: {}", err), format!("[error] in script execution: {}", err),
))); )));
} }
} }
@@ -1079,20 +1176,44 @@ impl AppState {
name: String, name: String,
rid: usize, rid: usize,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let mut main_config_file = self.config_file.clone();
main_config_file.pop();
let _ = self.main_tx.send(ToolMessage::Output((
rid,
format!("{} is the main config folder.", main_config_file.display()),
)));
let template_box = self.config.get("template_box").unwrap(); let template_box = self.config.get("template_box").unwrap();
let project_files = PathBuf::from(self.config.get("upcoming_files").unwrap()) let project_files = PathBuf::from(self.config.get("upcoming_files").unwrap())
.join(format!("{}/{}", org, name)); .join(format!("{}/{}", org, name));
let _ = self.main_tx.send(ToolMessage::Output((
rid,
format!("{} is the project_files folder", project_files.display()),
)));
let project_notes = PathBuf::from(self.config.get("upcoming_notes").unwrap()) let project_notes = PathBuf::from(self.config.get("upcoming_notes").unwrap())
.join(format!("{}/{}", org, name)); .join(format!("{}/{}", org, name));
let mut template_path = self.config_file.clone(); let _ = self.main_tx.send(ToolMessage::Output((
let mut project_conf_folder = self.config_file.clone(); rid,
format!("{} is the project_notes folder", project_notes.display()),
)));
let mut template_path = main_config_file.clone();
let mut project_conf_folder = main_config_file.clone();
let tools = self.config.get("tools").unwrap(); let tools = self.config.get("tools").unwrap();
template_path.pop();
template_path.push("note_templates"); template_path.push("note_templates");
project_conf_folder.pop(); let _ = self.main_tx.send(ToolMessage::Output((
rid,
format!("{} is the note template folder", template_path.display()),
)));
project_conf_folder.push(format!("projects/{}-{}", org, name)); project_conf_folder.push(format!("projects/{}-{}", org, name));
let _ = self.main_tx.send(ToolMessage::Output((
rid,
format!(
"{} is the project config folder",
project_conf_folder.display()
),
)));
let mut options = CopyOptions::new(); let mut options = CopyOptions::new();
options.overwrite = true; options.overwrite = true;
if !project_files.exists() {
match create_dir_all(&project_files) { match create_dir_all(&project_files) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@@ -1105,6 +1226,8 @@ impl AppState {
))); )));
} }
} }
}
if !project_notes.exists() {}
match create_dir_all(&project_notes) { match create_dir_all(&project_notes) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@@ -1117,6 +1240,7 @@ impl AppState {
))); )));
} }
} }
if !project_conf_folder.exists() {
match create_dir_all(&project_conf_folder) { match create_dir_all(&project_conf_folder) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@@ -1129,6 +1253,9 @@ impl AppState {
))); )));
} }
} }
}
let mut project_config_file = project_conf_folder.clone();
project_config_file.push("project.conf");
for entry in read_dir(template_path)? { for entry in read_dir(template_path)? {
let entry = entry?; let entry = entry?;
let template_name_os = entry.file_name(); let template_name_os = entry.file_name();
@@ -1179,11 +1306,20 @@ impl AppState {
notes: project_notes, notes: project_notes,
files: project_files, files: project_files,
hosts: Vec::new(), hosts: Vec::new(),
config_folder: project_conf_folder, config_folder: project_config_file,
current: false, current: false,
db: Some(db), db: Some(db),
scope: Vec::new(), scope: Vec::new(),
}; };
match new_project.save_config() {
Ok(_) => {}
Err(e) => {
let _ = self.main_tx.send(ToolMessage::Output((
0,
format!("[error] saving project! {e}"),
)));
}
}
new_project.save_config()?; new_project.save_config()?;
self.projects.push(new_project); self.projects.push(new_project);
return Ok(()); return Ok(());
@@ -1458,6 +1594,381 @@ impl AppState {
self.prompt.execute_command.clear(); self.prompt.execute_command.clear();
Ok(()) Ok(())
} }
pub fn parse_cs_portscan(&mut self) -> Result<(), Box<dyn Error>> {
if let Some(project) = self.projects.get_mut(self.selected_project) {
let walk = WalkDir::new(project.files.clone());
walk.into_iter().for_each(|res| {
if let Ok(entry) = res {
if entry.file_name().to_string_lossy().contains("services.tsv") {
if let Ok(scan) = read_to_string(entry.path()) {
let mut url_lines = Vec::new();
let mut web_host_lines = Vec::new();
let mut rdp_host_lines = Vec::new();
let mut ftp_host_lines = Vec::new();
let mut telnet_host_lines = Vec::new();
let mut winrm_host_lines = Vec::new();
let mut mysql_host_lines = Vec::new();
let mut mssql_host_lines = Vec::new();
let mut snmp_host_lines = Vec::new();
let mut kerberos_host_lines = Vec::new();
let mut ldap_host_lines = Vec::new();
let mut smb_host_lines = Vec::new();
let mut unknonw_host_lines = Vec::new();
let mut ssh_host_lines = Vec::new();
scan.lines().into_iter().for_each(|line| {
if line.len() > 0 {
let data: Vec<&str> = line.split_whitespace().collect();
match data[1].trim() {
"80" | "443" | "8080" | "8443" | "8000" | "4433" => {
let http_line =
format!("http://{}:{}", data[0], data[1]);
let https_line =
format!("https://{}:{}", data[0], data[1]);
url_lines.push(http_line);
url_lines.push(https_line);
web_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"3389" => {
rdp_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"21" => {
ftp_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"23" => {
telnet_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"22" => {
ssh_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"5985" | "5986" => {
winrm_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"3306" => {
mysql_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"1433" => {
mssql_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"161" => {
snmp_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"88" => {
kerberos_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"389" | "636" => {
ldap_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
"445" | "139" => {
smb_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
_ => {
unknonw_host_lines.push(data[0].to_string());
let mut existing = false;
project
.hosts
.iter_mut()
.filter(|h| h.ip == data[0].to_string())
.for_each(|h| {
h.add_port(data[1]);
existing = true;
});
if !existing {
let mut new_host = Host::new();
new_host.ip = data[0].trim().to_string();
new_host.add_port(data[1]);
project.add_host(new_host);
}
}
}
}
});
if !url_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("urls.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", url_lines.join("\n"));
}
}
if !web_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("web_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", web_host_lines.join("\n"));
}
}
if !rdp_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("rdp_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", rdp_host_lines.join("\n"));
}
}
if !ftp_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("ftp_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", ftp_host_lines.join("\n"));
}
}
if !telnet_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("telnet_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", telnet_host_lines.join("\n"));
}
}
if !winrm_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("winrm_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", winrm_host_lines.join("\n"));
}
}
if !mysql_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("mysql_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", mysql_host_lines.join("\n"));
}
}
if !mssql_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("mssql_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", mssql_host_lines.join("\n"));
}
}
if !snmp_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("snmp_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", snmp_host_lines.join("\n"));
}
}
if !kerberos_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("kerberos_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", kerberos_host_lines.join("\n"));
}
}
if !ldap_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("ldap_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", ldap_host_lines.join("\n"));
}
}
if !smb_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("smb_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", smb_host_lines.join("\n"));
}
}
if !unknonw_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("unknown_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", unknonw_host_lines.join("\n"));
}
}
if !ssh_host_lines.is_empty() {
let mut file_path = project.files.clone();
file_path.push("ssh_hosts.txt");
if let Ok(mut file) = File::create(file_path) {
let _ = write!(file, "{}", ssh_host_lines.join("\n"));
}
}
}
}
}
});
project.save_config()?;
}
Ok(())
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -1632,9 +2143,19 @@ impl Project {
self.hosts = hosts; self.hosts = hosts;
} }
pub fn add_host(&mut self, host: Host) { pub fn add_host(&mut self, mut host: Host) {
let mut new_id = 0;
self.hosts.iter().for_each(|h| {
if h.id > new_id {
new_id = h.id.clone();
}
});
new_id += 1;
if !self.hosts.iter().any(|h| h.ip == host.ip) {
host.id = new_id;
self.hosts.push(host); self.hosts.push(host);
} }
}
pub fn config_folder(&mut self, path: PathBuf) { pub fn config_folder(&mut self, path: PathBuf) {
self.config_folder = path; self.config_folder = path;
@@ -1681,11 +2202,11 @@ impl Project {
println!("{} | {} config loaded!", self.org_name, self.name); println!("{} | {} config loaded!", self.org_name, self.name);
println!("loading hosts..."); println!("loading hosts...");
} }
let mut hosts_folder = self.config_folder.clone(); let mut conf_folder = self.config_folder.clone();
let mut users_folder = self.config_folder.clone(); conf_folder.pop();
hosts_folder.pop(); let mut hosts_folder = conf_folder.clone();
let mut users_folder = conf_folder.clone();
hosts_folder.push("hosts"); hosts_folder.push("hosts");
users_folder.pop();
users_folder.push("users"); users_folder.push("users");
let mut users = HashMap::new(); let mut users = HashMap::new();
if users_folder.exists() { if users_folder.exists() {
@@ -1710,20 +2231,25 @@ impl Project {
} }
} }
if hosts_folder.exists() { if hosts_folder.exists() {
for entry in read_dir(hosts_folder)? { read_dir(hosts_folder)?.into_iter().for_each(|res| {
let entry = entry?; if let Ok(entry) = res {
let host_path = entry.path(); let host_path = entry.path();
let mut new_host = Host::new(); let mut new_host = Host::new();
let host_conf_text = read_to_string(host_path)?; println!("loading {}...", host_path.display());
for line in host_conf_text.lines() { if let Ok(host_conf_text) = read_to_string(host_path) {
host_conf_text.lines().into_iter().for_each(|line| {
if line.contains(": ") { if line.contains(": ") {
let (setting, data) = line.split_once(": ").unwrap(); let (setting, data) = line.split_once(": ").unwrap();
match setting.trim() { match setting.trim() {
"ip" => new_host.ip = data.trim().to_string(), "ip" => new_host.ip = data.trim().to_string(),
"hostname" => new_host.hostname = data.trim().to_string(), "hostname" => new_host.hostname = data.trim().to_string(),
"control_port" => new_host.control_port = data.trim().parse()?, "control_port" => {
"pwned" => new_host.pwned = data.trim().parse()?, new_host.control_port = data.trim().parse().unwrap();
"id" => new_host.id = data.trim().parse()?, }
"pwned" => {
new_host.pwned = data.trim().parse().unwrap();
}
"id" => new_host.id = data.trim().parse().unwrap(),
"findings" => { "findings" => {
new_host.findings = data new_host.findings = data
.trim() .trim()
@@ -1736,7 +2262,7 @@ impl Project {
.trim() .trim()
.split(",") .split(",")
.into_iter() .into_iter()
.map(|port| port.parse().unwrap()) .map(|port| port.parse().unwrap_or_default())
.collect::<Vec<usize>>() .collect::<Vec<usize>>()
} }
"users" => { "users" => {
@@ -1750,8 +2276,11 @@ impl Project {
_ => {} _ => {}
} }
} }
});
self.add_host(new_host);
} }
} }
});
} }
if display { if display {
println!("{} | {} loaded!", self.org_name, self.name); println!("{} | {} loaded!", self.org_name, self.name);
@@ -1760,16 +2289,29 @@ impl Project {
} }
pub fn save_config(&mut self) -> Result<(), Box<dyn Error>> { pub fn save_config(&mut self) -> Result<(), Box<dyn Error>> {
create_dir_all(&self.config_folder)?; let mut conf_folder = self.config_folder.clone();
let mut hosts_folder = self.config_folder.clone(); conf_folder.pop();
if !conf_folder.exists() {
match create_dir_all(&conf_folder) {
Ok(_) => {}
Err(e) => {
return Err(
format!("save_config: couldn't create project conf folder! {e}").into(),
);
}
}
}
let mut hosts_folder = conf_folder.clone();
hosts_folder.push("hosts"); hosts_folder.push("hosts");
let mut users_folder = self.config_folder.clone(); let mut users_folder = conf_folder.clone();
users_folder.push("users"); users_folder.push("users");
if !hosts_folder.exists() {
create_dir_all(&hosts_folder)?; create_dir_all(&hosts_folder)?;
}
if !users_folder.exists() {
create_dir_all(&users_folder)?; create_dir_all(&users_folder)?;
let mut conf_file = self.config_folder.clone(); }
conf_file.push("project.conf"); let mut file = File::create(&self.config_folder)?;
let mut file = File::create(conf_file)?;
let mut out_string = format!( let mut out_string = format!(
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\n", "org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\n",
self.org_name, self.org_name,
@@ -1784,67 +2326,13 @@ impl Project {
out_string.push_str("stage: upcoming"); out_string.push_str("stage: upcoming");
} }
file.write_all(out_string.as_bytes())?; file.write_all(out_string.as_bytes())?;
if !self.hosts.is_empty() { self.hosts
for host in &self.hosts { .iter_mut()
let mut host_conf_file = .try_for_each(|h| -> Result<(), Box<dyn Error>> {
File::create(hosts_folder.join(format!("{}.conf", host.id)))?; let mut host_path = hosts_folder.clone();
let mut out_string = format!( host_path.push(format!("{}.conf", h.id));
" h.save_config_file(host_path)
ip: {} })?;
hostname: {}
control_port: {}
pwned: {}
id: {}",
host.ip, host.hostname, host.control_port, host.pwned, host.id,
);
if !host.findings.is_empty() {
out_string.push_str(&format!("\nfindings: "));
out_string.push_str(&host.findings.join(","));
}
if !host.open_ports.is_empty() {
out_string.push_str(&format!("\nopen_ports: "));
out_string.push_str(
&host
.open_ports
.iter()
.map(|port| port.to_string())
.collect::<Vec<String>>()
.join(","),
);
}
if !host.users.is_empty() {
out_string.push_str(&format!("\nusers: "));
out_string.push_str(
&host
.users
.iter()
.map(|user| user.name.clone())
.collect::<Vec<String>>()
.join(","),
);
for user in &host.users {
let mut user_conf_file =
File::create(users_folder.join(format!("{}.conf", user.name)))?;
let mut user_string = format!("username: {}", &user.name);
user_string.push_str(&format!("\ncompromised: {}", user.compromised));
if user.hash.is_some() {
let hash = user.hash.clone().unwrap();
user_string.push_str(&format!("hash: {hash}"));
}
if user.password.is_some() {
let password = user.password.clone().unwrap();
user_string.push_str(&format!("password: {password}"));
}
if user.ticket.is_some() {
let ticket = user.ticket.clone().unwrap().display().to_string();
user_string.push_str(&format!("ticket: {ticket}"));
}
user_conf_file.write_all(user_string.as_bytes())?;
}
}
host_conf_file.write_all(out_string.as_bytes())?;
}
}
return Ok(()); return Ok(());
} }
} }
@@ -1922,9 +2410,13 @@ impl Host {
self.findings = findings; self.findings = findings;
} }
pub fn add_port(&mut self, port: usize) { pub fn add_port(&mut self, port: &str) {
if let Ok(port) = port.trim().parse() {
if !self.open_ports.contains(&port) {
self.open_ports.push(port); self.open_ports.push(port);
} }
}
}
pub fn add_user(&mut self, user: User) { pub fn add_user(&mut self, user: User) {
self.users.push(user); self.users.push(user);
@@ -1933,6 +2425,37 @@ impl Host {
pub fn add_finding(&mut self, finding: String) { pub fn add_finding(&mut self, finding: String) {
self.findings.push(finding); self.findings.push(finding);
} }
pub fn save_config_file(&mut self, path: PathBuf) -> Result<(), Box<dyn Error>> {
let mut host_file = File::create(path)?;
let mut out_string = format!(
"
ip: {}
hostname: {}
control_port: {}
pwned: {}
id: {}",
self.ip, self.hostname, self.control_port, self.pwned, self.id
);
if !self.findings.is_empty() {
out_string.push_str(&format!("\nfindings: "));
out_string.push_str(&self.findings.join(","));
}
if !self.open_ports.is_empty() {
out_string.push_str("\nopen_ports: ");
out_string.push_str(
&self
.open_ports
.iter()
.map(|port| port.to_string())
.collect::<Vec<String>>()
.join(","),
);
}
write!(host_file, "{}", out_string)?;
host_file.sync_all()?;
Ok(())
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -2034,12 +2557,12 @@ impl ModuleLoader {
engine.register_fn("get_host", |hosts: &mut Vec<Host>, index: i64| { engine.register_fn("get_host", |hosts: &mut Vec<Host>, index: i64| {
hosts.get(index as usize).cloned().unwrap_or_else(Host::new) hosts.get(index as usize).cloned().unwrap_or_else(Host::new)
}); });
engine.register_fn("Host", Host::new); engine.register_fn("new_host", Host::new);
engine.register_fn("open_file", |path: &str| { engine.register_fn("open_file", |path: &str| {
std::fs::read_to_string(path).unwrap_or_else(|_| String::new()) std::fs::read_to_string(path).unwrap_or_else(|_| String::new())
}); });
engine.register_fn("add_port", |host: &mut Host, port: i64| { engine.register_fn("add_port", |host: &mut Host, port: i64| {
host.add_port(port as usize); host.add_port(format!("{}", port).as_str());
}); });
engine.register_fn("expand_target", |s: &str| -> rhai::Array { engine.register_fn("expand_target", |s: &str| -> rhai::Array {
let mut results = rhai::Array::new(); let mut results = rhai::Array::new();
@@ -2096,6 +2619,13 @@ impl ModuleLoader {
} }
return out_string; return out_string;
}); });
engine.register_fn("db_run", |p: &mut Project, command: String| -> String {
let mut out_string = format!("No distrobox configured for selected project.");
if let Some(db) = p.db.clone() {
out_string = db.run_command(&command);
}
return out_string;
});
Self { Self {
engine: Arc::new(engine), engine: Arc::new(engine),
commands: HashMap::new(), commands: HashMap::new(),
@@ -2317,7 +2847,6 @@ impl DistroBox {
let reader = BufReader::new(stdout); let reader = BufReader::new(stdout);
for line in reader.lines().flatten() { for line in reader.lines().flatten() {
let _ = tx_out.send(ToolMessage::Output((rid, line.clone()))); let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
println!("{}", line);
} }
}); });
} }
@@ -2327,7 +2856,6 @@ impl DistroBox {
let reader = BufReader::new(stderr); let reader = BufReader::new(stderr);
for line in reader.lines().flatten() { for line in reader.lines().flatten() {
let _ = tx_out.send(ToolMessage::Output((rid, line.clone()))); let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
println!("{}", line);
} }
}); });
} }
@@ -2382,6 +2910,26 @@ impl DistroBox {
let _ = term_cmd.spawn(); let _ = term_cmd.spawn();
} }
} }
pub fn run_command(&self, cmd: &str) -> String {
let output = Command::new("distrobox")
.arg("enter")
.arg("-e")
.arg(format!("\"{}\"", cmd))
.output();
match output {
Ok(output) => {
if output.status.success() {
return String::from_utf8_lossy(&output.stdout).to_string();
} else {
return format!("[error] {}", String::from_utf8_lossy(&output.stdout));
}
}
Err(e) => {
return format!("[error] {e}");
}
}
}
} }
#[derive(Clone)] #[derive(Clone)]
+88
View File
@@ -0,0 +1,88 @@
use crate::*;
use anyhow::Context;
use headless_chrome::{Browser, LaunchOptions};
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
pub fn rustwitness(
input: PathBuf,
output: PathBuf,
proxy: Option<String>,
tx: Sender<ToolMessage>,
) {
fn capture_screenshot(
url: &str,
proxy: Option<String>,
output: PathBuf,
) -> Result<(), Box<dyn Error>> {
if !output.exists() {
create_dir_all(&output)?;
}
let mut launch_options = LaunchOptions::default();
let file_name = url.split("://").collect::<Vec<&str>>()[1].to_string();
if let Some(ref proxy_url) = proxy {
let proxy_arg = format!("--proxy-server={}", proxy_url);
launch_options
.args
.push(std::ffi::OsStr::new(Box::leak(proxy_arg.into_boxed_str())));
}
let browser = Browser::new(launch_options).context("Browser launch failed")?;
let tab = browser.new_tab().context("Failed to open tab")?;
tab.navigate_to(url).context("Navigation failed")?;
tab.wait_until_navigated()
.context("Waiting for load failed")?;
tab.wait_for_element("body")?;
tab.evaluate("document.readyState === 'complete'", false)?;
let mut file_path = output.clone();
let mut log_path = output.clone();
log_path.push("log.txt");
file_path.push(format!("{}.png", file_name));
let png_data = tab
.capture_screenshot(
headless_chrome::protocol::cdp::Page::CaptureScreenshotFormatOption::Png,
None,
None,
true,
)
.context("Screenshot capture failed")?;
fs::write(&file_path, png_data)
.context("Failed to write file")
.context(format!(
"failed to write png file! {}",
&file_path.display()
))?;
println!("Successfully captured: {}", url);
fs::write(&log_path, format!("{}\n", url).as_bytes())
.context("failed to write log file!")?;
Ok(())
}
match File::open(&input) {
Ok(file) => {
let urls: Vec<String> = BufReader::new(file)
.lines()
.filter_map(|line| line.ok())
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();
let _ = tx.send(ToolMessage::Output((
0,
format!("Starting capture of {} urls...", urls.len()),
)));
urls.par_iter().enumerate().for_each(|(_index, url)| {
if let Err(e) = capture_screenshot(url, proxy.clone(), output.clone()) {
let _ = tx.send(ToolMessage::Output((
0,
format!("[error] rustwitness: Failed to process {}: {:?}", url, e),
)));
}
});
let _ = tx.send(ToolMessage::Output((
0,
"[success] all urls scanned for screenshots!".to_string(),
)));
}
Err(e) => {
let _ = tx.send(ToolMessage::Output((0, format!("[error] rustwitness {e}"))));
}
}
}
+45
View File
@@ -22,6 +22,7 @@ use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer};
enum ClientAction { enum ClientAction {
Output(String), Output(String),
Cmd(String), Cmd(String),
Collab(String),
} }
pub struct Client { pub struct Client {
@@ -31,6 +32,7 @@ pub struct Client {
actions: Vec<ClientAction>, actions: Vec<ClientAction>,
controlling: usize, controlling: usize,
controlled: usize, controlled: usize,
collabing: Vec<usize>,
output_que: Vec<String>, output_que: Vec<String>,
logged_in: bool, logged_in: bool,
timer: Duration, timer: Duration,
@@ -201,6 +203,7 @@ where
actions: Vec::new(), actions: Vec::new(),
controlled: 0, controlled: 0,
controlling: 0, controlling: 0,
collabing: Vec::new(),
output_que: Vec::new(), output_que: Vec::new(),
logged_in: false, logged_in: false,
timer: Duration::from_secs(5), timer: Duration::from_secs(5),
@@ -312,6 +315,26 @@ where
dest_client.id, cmd dest_client.id, cmd
))); )));
} }
else{
let mut colabs = Vec::new();
lock.clients.iter_mut().filter(|c| c.id == source_id).for_each(|c|{
if c.collabing.is_empty(){
c.actions.push(ClientAction::Output("Error no controlled or collabed clients associated with you!".to_string()));
}
else{
c.collabing.iter().for_each(|id|{
colabs.push(id.clone());
});
}
});
if !colabs.is_empty(){
colabs.iter().for_each(|id|{
lock.clients.iter_mut().filter(|c| &c.id == id).for_each(|c|{
c.actions.push(ClientAction::Cmd(data.to_string()));
});
});
}
}
} }
"CONTROL" => { "CONTROL" => {
let new_control_id = data.trim().parse::<usize>().unwrap(); let new_control_id = data.trim().parse::<usize>().unwrap();
@@ -429,6 +452,22 @@ where
c.remove = true; c.remove = true;
}); });
} }
"COLLAB" => {
let dest_id: usize = data.trim().parse().unwrap();
lock.clients
.iter_mut()
.filter(|c| c.id == source_id)
.for_each(|c| {
c.collabing.push(dest_id.clone());
});
lock.clients
.iter_mut()
.filter(|d| d.id == dest_id)
.for_each(|d| {
d.collabing.push(dest_id.clone());
});
println!("{} is collabing with {}", source_id, dest_id);
}
"SLEEP" => { "SLEEP" => {
if let Ok(secs) = data.parse::<u64>() { if let Ok(secs) = data.parse::<u64>() {
lock.clients lock.clients
@@ -455,6 +494,9 @@ where
println!("adding {} to output", text); println!("adding {} to output", text);
messages.push(format!("OUTPUT|{}", text)); messages.push(format!("OUTPUT|{}", text));
} }
ClientAction::Collab(text) => {
println!("todo");
}
} }
} }
let full_message = messages.join("||"); let full_message = messages.join("||");
@@ -523,6 +565,9 @@ where
println!("adding {} to output", text); println!("adding {} to output", text);
messages.push(format!("OUTPUT|{}", text)); messages.push(format!("OUTPUT|{}", text));
} }
ClientAction::Collab(text) => {
println!("todo");
}
} }
} }
let full_message = messages.join("||"); let full_message = messages.join("||");