good solution to bars flashing implemented

This commit is contained in:
epi
2021-01-10 08:00:20 -06:00
parent 5b23ce2a24
commit c6b919b4fd
4 changed files with 66 additions and 55 deletions

View File

@@ -2,12 +2,11 @@ use crossterm::event::{self, Event, KeyCode};
use feroxbuster::{
banner,
config::{CONFIGURATION, PROGRESS_BAR, PROGRESS_PRINTER},
extractor::{extract_robots_txt, request_feroxresponse_from_new_link},
heuristics, logger,
progress::{add_bar, BarType},
reporter,
scan_manager::{self, ScanStatus, PAUSE_SCAN},
scanner::{self, scan_url, send_report, RESPONSES, SCANNED_URLS},
scanner::{self, scan_url, RESPONSES, SCANNED_URLS},
statistics::{
self,
StatCommand::{self, CreateBar, LoadStats, UpdateUsizeField},
@@ -110,7 +109,7 @@ fn get_unique_words_from_wordlist(path: &str) -> FeroxResult<Arc<HashSet<String>
/// Determine whether it's a single url scan or urls are coming from stdin, then scan as needed
async fn scan(
mut targets: Vec<String>,
targets: Vec<String>,
stats: Arc<Stats>,
tx_term: UnboundedSender<FeroxResponse>,
tx_file: UnboundedSender<FeroxResponse>,
@@ -175,43 +174,6 @@ async fn scan(
}
}
if CONFIGURATION.extract_links {
// todo can i somehow get these to be abortable?
for target in targets.clone() {
// modifying the targets vector, so we can't have a reference to it while we borrow
// it as mutable; thus the clone
let robots_links = extract_robots_txt(&target, &CONFIGURATION, tx_stats.clone()).await;
for robot_link in robots_links {
// create a url based on the given command line options, continue on error
let ferox_response = match request_feroxresponse_from_new_link(
&robot_link,
tx_stats.clone(),
)
.await
{
Some(resp) => resp,
None => continue,
};
if ferox_response.is_file() {
SCANNED_URLS.add_file_scan(&robot_link, stats.clone());
send_report(tx_term.clone(), ferox_response);
} else {
let (unknown, _) = SCANNED_URLS.add_directory_scan(&robot_link, stats.clone());
if !unknown {
// known directory; can skip (unlikely)
continue;
}
// unknown directory; add to targets for scanning
targets.push(robot_link);
}
}
}
}
let mut tasks = vec![];
for target in targets {

View File

@@ -1,13 +1,12 @@
use crate::{
config::{CONFIGURATION, PROGRESS_PRINTER},
scan_manager::PAUSE_SCAN,
scanner::RESPONSES,
statistics::{
StatCommand::{self, UpdateUsizeField},
StatField::ResourcesDiscovered,
},
utils::{ferox_print, make_request, open_file},
FeroxChannel, FeroxResponse, FeroxSerialize, SLEEP_DURATION,
FeroxChannel, FeroxResponse, FeroxSerialize,
};
use console::strip_ansi_codes;
use std::{
@@ -18,7 +17,6 @@ use std::{
use tokio::{
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
task::JoinHandle,
time::{self, Duration},
};
/// Singleton buffered file behind an Arc/RwLock; used for file writes from two locations:
@@ -115,11 +113,6 @@ async fn spawn_terminal_reporter(
);
while let Some(mut resp) = resp_chan.recv().await {
while PAUSE_SCAN.load(std::sync::atomic::Ordering::SeqCst) {
// todo this line isn't under test
time::sleep(Duration::from_millis(SLEEP_DURATION)).await;
}
log::trace!("received {} on reporting channel", resp.url());
let contains_sentry = CONFIGURATION.status_codes.contains(&resp.status().as_u16());

View File

@@ -1,5 +1,5 @@
use crate::{
config::{Configuration, CONFIGURATION, PROGRESS_PRINTER},
config::{Configuration, CONFIGURATION, PROGRESS_BAR, PROGRESS_PRINTER},
parser::TIMESPEC_REGEX,
progress::{add_bar, BarType},
reporter::safe_file_write,
@@ -9,7 +9,7 @@ use crate::{
FeroxResponse, FeroxSerialize, SLEEP_DURATION,
};
use console::{style, Term};
use indicatif::ProgressBar;
use indicatif::{ProgressBar, ProgressDrawTarget};
use serde::{
ser::{SerializeSeq, SerializeStruct},
Deserialize, Deserializer, Serialize, Serializer,
@@ -436,6 +436,9 @@ impl FeroxScans {
self.display_scans(&term).await;
// todo utf8 lines like the banner
// todo add a header and not just the scans first thing
// todo break out logic from loop for testing
let border = "==============================================================";
term_write!(term, border);
@@ -450,7 +453,7 @@ impl FeroxScans {
term_write!(term, &instructions);
term_write!(term, border);
let input = term.read_char()?;
let input = term.read_char()?; // todo change to line at least for the scan entry
if input == 'r' {
term_write!(term, "Resuming scans...");
@@ -540,13 +543,14 @@ impl FeroxScans {
INTERACTIVE_BARRIER.fetch_add(1, Ordering::Relaxed);
if get_user_input {
PROGRESS_BAR.set_draw_target(ProgressDrawTarget::hidden());
// todo test this block (if possible)
// the first clear screen happens and then there's another tick from the existing
// progress bars. A clear, brief pause, clear is used to present the user with a
// clean menu
clear_screen!(term);
time::sleep(Duration::from_millis(SLEEP_DURATION / 2)).await;
time::sleep(Duration::from_millis(SLEEP_DURATION)).await;
clear_screen!(term);
// interactive_menu is a blocking interactive loop
@@ -578,6 +582,7 @@ impl FeroxScans {
if INTERACTIVE_BARRIER.load(Ordering::Relaxed) == 1 {
INTERACTIVE_BARRIER.fetch_sub(1, Ordering::Relaxed);
PROGRESS_BAR.set_draw_target(ProgressDrawTarget::stdout());
}
log::trace!("exit: pause_scan");

View File

@@ -1,13 +1,12 @@
use crate::scan_manager::ScanStatus;
use crate::{
config::{Configuration, CONFIGURATION},
extractor::{get_links, request_feroxresponse_from_new_link},
extractor::{extract_robots_txt, get_links, request_feroxresponse_from_new_link},
filters::{
FeroxFilter, LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter,
WildcardFilter, WordsFilter,
},
heuristics,
scan_manager::{FeroxResponses, FeroxScans, PAUSE_SCAN},
scan_manager::{FeroxResponses, FeroxScans, ScanStatus, PAUSE_SCAN},
statistics::{
StatCommand::{self, UpdateF64Field, UpdateUsizeField},
StatField::{DirScanTimes, ExpectedPerScan, TotalScans, WildcardsFiltered},
@@ -499,6 +498,44 @@ pub fn send_report(report_sender: UnboundedSender<FeroxResponse>, response: Fero
log::trace!("exit: send_report");
}
/// todo
async fn scan_robots_txt(
target_url: &str,
stats: Arc<Stats>,
tx_term: UnboundedSender<FeroxResponse>,
tx_dir: UnboundedSender<String>,
tx_stats: UnboundedSender<StatCommand>,
) {
// todo trace
let robots_links = extract_robots_txt(&target_url, &CONFIGURATION, tx_stats.clone()).await;
for robot_link in robots_links {
// create a url based on the given command line options, continue on error
let ferox_response =
match request_feroxresponse_from_new_link(&robot_link, tx_stats.clone()).await {
Some(resp) => resp,
None => continue,
};
if ferox_response.is_file() {
SCANNED_URLS.add_file_scan(&robot_link, stats.clone());
send_report(tx_term.clone(), ferox_response);
} else {
let (unknown, _) = SCANNED_URLS.add_directory_scan(&robot_link, stats.clone());
if !unknown {
// known directory; can skip (unlikely)
continue;
}
// unknown directory; add to targets for scanning
if let Err(e) = tx_dir.send(robot_link) {
log::error!("Could not send extracted link to recursion handler: {}", e);
}
}
}
}
/// Scan a given url using a given wordlist
///
/// This is the primary entrypoint for the scanner
@@ -531,6 +568,20 @@ pub async fn scan_url(
if CALL_COUNT.load(Ordering::Relaxed) < stats.initial_targets.load(Ordering::Relaxed) {
CALL_COUNT.fetch_add(1, Ordering::Relaxed);
if CONFIGURATION.extract_links && CALL_COUNT.load(Ordering::Relaxed) == 1 {
// only grab robots.txt on the first scan_url call. all fresh dirs will be passed
// to the recursion thread
log::error!("calling robots");
scan_robots_txt(
target_url,
stats.clone(),
tx_term.clone(),
tx_dir.clone(),
tx_stats.clone(),
)
.await;
}
update_stat!(tx_stats, UpdateUsizeField(TotalScans, 1));
// this protection allows us to add the first scanned url to SCANNED_URLS