diff --git a/Cargo.lock b/Cargo.lock index c344e091..6adf7910 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,7 +173,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix", + "rustix 0.38.44", "slab", "tracing", "windows-sys 0.59.0", @@ -268,9 +268,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blocking" @@ -324,6 +324,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "ciborium" version = "0.2.2" @@ -439,6 +445,21 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "coolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "980c2afde4af43d6a05c5be738f9eae595cff86dce1f38f88b95058a98c027f3" + [[package]] name = "criterion" version = "0.7.0" @@ -497,6 +518,33 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.1.3", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crunchy" version = "0.2.3" @@ -509,6 +557,28 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "dirs" version = "6.0.0" @@ -541,6 +611,15 @@ dependencies = [ "syn", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "either" version = "1.13.0" @@ -1145,9 +1224,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libredox" @@ -1171,12 +1250,24 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.12" @@ -1233,10 +1324,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1409,7 +1513,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix", + "rustix 0.38.44", "tracing", "windows-sys 0.59.0", ] @@ -1630,6 +1734,15 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1639,7 +1752,20 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.11.0", "windows-sys 0.59.0", ] @@ -1700,6 +1826,7 @@ dependencies = [ "rlimit", "serde", "serde_derive", + "terminal-light", "text_placeholder", "toml", "wait-timeout", @@ -1742,6 +1869,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.225" @@ -1799,6 +1932,37 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1858,13 +2022,25 @@ dependencies = [ "syn", ] +[[package]] +name = "terminal-light" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f76be906d875a0ce764c52a055858c24847cb7dc674d3a5ad8cf7e3dd4ee9f" +dependencies = [ + "coolor", + "crossterm", + "thiserror 1.0.69", + "xterm-query", +] + [[package]] name = "terminal_size" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ - "rustix", + "rustix 0.38.44", "windows-sys 0.59.0", ] @@ -2055,6 +2231,12 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "untrusted" version = "0.9.0" @@ -2439,6 +2621,16 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "xterm-query" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "292c33df434fde4ecd87a7afecdfa1681a3d29567fc69c774a0d83d32c095331" +dependencies = [ + "nix", + "thiserror 1.0.69", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index c6d47183..410e0949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ serde_derive = "1.0.116" cidr-utils = "0.6.1" itertools = "0.14.0" hickory-resolver = { version = "0.24.3", features = ["dns-over-rustls"] } +terminal-light = "1.8.0" anyhow = "1.0.40" text_placeholder = { version = "0.5", features = ["struct_context"] } once_cell = "1.21.3" diff --git a/src/main.rs b/src/main.rs index 08e6eaf8..e9321b16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,10 @@ use rustscan::address::parse_addresses; extern crate colorful; extern crate dirs; +/// Luma threshold for distinguishing light vs dark terminals. +/// Values above this indicate a light background. +const LIGHT_TERMINAL_THRESHOLD: f32 = 0.6; + // Average value for Ubuntu #[cfg(unix)] const DEFAULT_FILE_DESCRIPTORS_LIMIT: usize = 8000; @@ -191,22 +195,56 @@ fn main() { info!("{}", benchmarks.summary()); } +/// Detects whether the terminal has a light background. +/// +/// Uses the terminal's reported background color luminance to determine +/// if a light color scheme should be used. Returns `false` (dark theme) +/// if detection fails, as most terminals use dark backgrounds. +fn is_light_terminal() -> bool { + match terminal_light::luma() { + Ok(luma) => { + debug!("Detected terminal luma: {luma:.2}"); + luma > LIGHT_TERMINAL_THRESHOLD + } + Err(e) => { + debug!("Could not detect terminal theme: {e:?}, defaulting to dark"); + false + } + } +} + +/// Returns the appropriate banner colors based on terminal background. +/// +/// For dark terminals: bright green banner, yellow info box +/// For light terminals: dark blue banner, dark orange info box +fn banner_colors(is_light: bool) -> (Color, Color) { + if is_light { + (Color::DarkBlue, Color::DarkOrange3a) + } else { + (Color::Green, Color::Yellow) + } +} + /// Prints the opening title of RustScan #[allow(clippy::items_after_statements, clippy::needless_raw_string_hashes)] fn print_opening(opts: &Opts) { debug!("Printing opening"); + + let is_light = is_light_terminal(); + let (banner_color, info_color) = banner_colors(is_light); + let s = r#".----. .-. .-. .----..---. .----. .---. .--. .-. .-. | {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| | | .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ | `-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-' The Modern Day Port Scanner."#; - println!("{}", s.gradient(Color::Green).bold()); + println!("{}", s.gradient(banner_color).bold()); let info = r#"________________________________________ : http://discord.skerritt.blog : : https://github.com/RustScan/RustScan : --------------------------------------"#; - println!("{}", info.gradient(Color::Yellow).bold()); + println!("{}", info.gradient(info_color).bold()); funny_opening!(); let config_path = opts @@ -299,7 +337,8 @@ fn infer_batch_size(opts: &Opts, ulimit: usize) -> usize { mod tests { #[cfg(unix)] use super::{adjust_ulimit_size, infer_batch_size}; - use super::{print_opening, Opts}; + use super::{banner_colors, print_opening, Opts}; + use colorful::Color; #[test] #[cfg(unix)] @@ -374,4 +413,18 @@ mod tests { // print opening should not panic print_opening(&opts); } + + #[test] + fn test_banner_colors_dark_terminal() { + let (banner, info) = banner_colors(false); + assert!(matches!(banner, Color::Green)); + assert!(matches!(info, Color::Yellow)); + } + + #[test] + fn test_banner_colors_light_terminal() { + let (banner, info) = banner_colors(true); + assert!(matches!(banner, Color::DarkBlue)); + assert!(matches!(info, Color::DarkOrange3a)); + } }