mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-06-07 10:01:12 -03:00
good solution to bars flashing implemented
This commit is contained in:
42
src/main.rs
42
src/main.rs
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user