diff --git a/Cargo.toml b/Cargo.toml index f68f688..7afb0f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ serde = { version = "1.0", features = ["derive"] } uuid = { version = "0.8", features = ["v4"] } ansi_term = "0.12" indicatif = "0.15" +console = "0.12" [dev-dependencies] tempfile = "3.1" diff --git a/src/config.rs b/src/config.rs index 0f77efd..6cb3933 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,7 +2,7 @@ use crate::utils::status_colorizer; use crate::{client, parser, progress}; use crate::{DEFAULT_CONFIG_NAME, DEFAULT_STATUS_CODES, DEFAULT_WORDLIST, VERSION}; use clap::value_t; -use indicatif::{MultiProgress, ProgressBar}; +use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget}; use lazy_static::lazy_static; use reqwest::{Client, StatusCode}; use serde::Deserialize; @@ -17,7 +17,7 @@ lazy_static! { pub static ref CONFIGURATION: Configuration = Configuration::new(); /// Global progress bar that houses other progress bars - pub static ref PROGRESS_BAR: MultiProgress = MultiProgress::new(); + pub static ref PROGRESS_BAR: MultiProgress = MultiProgress::with_draw_target(ProgressDrawTarget::stdout()); /// Global progress bar that is only used for printing messages that don't jack up other bars pub static ref PROGRESS_PRINTER: ProgressBar = progress::add_bar("", 0, true); diff --git a/src/heuristics.rs b/src/heuristics.rs index 929df02..1e7354c 100644 --- a/src/heuristics.rs +++ b/src/heuristics.rs @@ -1,6 +1,6 @@ use crate::config::{CONFIGURATION, PROGRESS_PRINTER}; use crate::scanner::{format_url, make_request}; -use crate::utils::{get_url_path_length, status_colorizer}; +use crate::utils::{get_url_path_length, status_colorizer, ferox_print}; use ansi_term::Color::{Cyan, Yellow}; use indicatif::ProgressBar; use reqwest::Response; @@ -81,29 +81,29 @@ pub async fn wildcard_test(target_url: &str, bar: ProgressBar) -> Option10} Wildcard response is dynamic; {} ({} + url length) responses; toggle this behavior by using {}", status_colorizer("WLD"), wc_length - url_len, Yellow.paint("auto-filtering"), Cyan.paint(format!("{}", wc_length - url_len)), Yellow.paint("--dontfilter") - ) + ), &PROGRESS_PRINTER ); } wildcard.dynamic = wc_length - url_len; } else if wc_length == wc2_length { if !CONFIGURATION.quiet { - PROGRESS_PRINTER.println(format!( + ferox_print(&format!( "{} {:>10} Wildcard response is static; {} {} responses; toggle this behavior by using {}", status_colorizer("WLD"), wc_length, Yellow.paint("auto-filtering"), Cyan.paint(format!("{}", wc_length)), Yellow.paint("--dontfilter") - )); + ), &PROGRESS_PRINTER); } wildcard.size = wc_length; } @@ -158,37 +158,37 @@ async fn make_wildcard_request(target_url: &str, length: usize) -> Option10} Got {} for {} (url length: {})", wildcard, content_len, status_colorizer(&response.status().as_str()), response.url(), url_len - )); + ), &PROGRESS_PRINTER); } if response.status().is_redirection() { // show where it goes, if possible if let Some(next_loc) = response.headers().get("Location") { if let Ok(next_loc_str) = next_loc.to_str() { if !CONFIGURATION.quiet { - PROGRESS_PRINTER.println(format!( + ferox_print(&format!( "{} {:>10} {} redirects to => {}", wildcard, content_len, response.url(), next_loc_str - )); + ), &PROGRESS_PRINTER); } } else { if !CONFIGURATION.quiet { - PROGRESS_PRINTER.println(format!( + ferox_print(&format!( "{} {:>10} {} redirects to => {:?}", wildcard, content_len, response.url(), next_loc - )); + ), &PROGRESS_PRINTER); } } } @@ -238,8 +238,7 @@ pub async fn connectivity_test(target_urls: &[String]) -> Vec { } Err(e) => { if !CONFIGURATION.quiet { - PROGRESS_PRINTER - .println(format!("Could not connect to {}, skipping...", target_url)); + ferox_print(&format!("Could not connect to {}, skipping...", target_url), &PROGRESS_PRINTER); } log::error!("{}", e); } diff --git a/src/progress.rs b/src/progress.rs index b4a846e..ec0eedd 100644 --- a/src/progress.rs +++ b/src/progress.rs @@ -1,5 +1,5 @@ use crate::config::{PROGRESS_BAR, CONFIGURATION}; -use indicatif::{ProgressBar, ProgressStyle}; +use indicatif::{ProgressBar, ProgressStyle, ProgressDrawTarget}; pub fn add_bar(prefix: &str, length: u64, hidden: bool) -> ProgressBar { let style = if hidden || CONFIGURATION.quiet { diff --git a/src/scanner.rs b/src/scanner.rs index 76f65ea..ae78698 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -1,6 +1,6 @@ use crate::config::{CONFIGURATION, PROGRESS_BAR, PROGRESS_PRINTER}; use crate::heuristics::WildcardFilter; -use crate::utils::{get_current_depth, get_url_path_length, status_colorizer}; +use crate::utils::{get_current_depth, get_url_path_length, status_colorizer, ferox_print}; use crate::{heuristics, progress, FeroxResult}; use futures::future::{BoxFuture, FutureExt}; use futures::{stream, StreamExt}; @@ -189,17 +189,17 @@ async fn spawn_terminal_reporter(mut report_channel: UnboundedReceiver if CONFIGURATION.statuscodes.contains(&resp.status().as_u16()) { if CONFIGURATION.quiet { - PROGRESS_PRINTER.println(format!("{}", resp.url())); + ferox_print(&format!("{}", resp.url()), &PROGRESS_PRINTER); } else { let status = status_colorizer(&resp.status().as_str()); - PROGRESS_PRINTER.println(format!( + ferox_print(&format!( // example output // 200 3280 https://localhost.com/FAQ "{} {:>10} {}", status, resp.content_length().unwrap_or(0), resp.url() - )); + ), &PROGRESS_PRINTER); } } log::debug!("report complete: {}", resp.url()); diff --git a/src/utils.rs b/src/utils.rs index 951f854..c0825ce 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,8 @@ use ansi_term::Color::{Blue, Cyan, Green, Red, Yellow}; use reqwest::Url; use std::convert::TryInto; +use console::{user_attended, strip_ansi_codes}; +use indicatif::ProgressBar; /// Helper function that determines the current depth of a given url /// @@ -105,6 +107,25 @@ pub fn get_url_path_length(url: &Url) -> u64 { 0 } +/// Simple helper to abstract away the check for an attached terminal. +/// +/// If a terminal is attached, progress bars are visible and the progress bar is used to print +/// to stderr. The progress bar must be used when bars are visible in order to not jack up any +/// progress bar output (the bar knows how to print above itself) +/// +/// If a terminal is not attached, `msg` is printed to stdout, with its ansi +/// color codes stripped. +/// +/// additionally, provides a location for future printing options (no color, etc) to be handled +pub fn ferox_print(msg: &str, bar: &ProgressBar) { + if user_attended() { + bar.println(msg); + } else { + let stripped = strip_ansi_codes(msg); + println!("{}", stripped); + } +} + #[cfg(test)] mod tests { use super::*;