diff --git a/src/client.rs b/src/client.rs index d8f1158..1f80a3d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -73,9 +73,7 @@ where let identity = reqwest::Identity::from_pkcs8_pem(&cert, &key).with_context(|| { format!( - "either {} or {} are invalid; expecting PEM encoded certificate and key", - cert_path, key_path - ) + "either {cert_path} or {key_path} are invalid; expecting PEM encoded certificate and key") })?; client = client.identity(identity); diff --git a/src/config/container.rs b/src/config/container.rs index 3bbb200..567dfdb 100644 --- a/src/config/container.rs +++ b/src/config/container.rs @@ -1020,7 +1020,7 @@ impl Configuration { // Split into name and value at the first equals sign let name = &trimmed[..pos].trim(); let value = &trimmed[pos + 1..].trim(); - Some(format!("{}={}", name, value)) + Some(format!("{name}={value}")) } else { // Handle the case where there's no equals sign Some(trimmed.to_string()) diff --git a/src/config/utils.rs b/src/config/utils.rs index 128249d..08d8b9a 100644 --- a/src/config/utils.rs +++ b/src/config/utils.rs @@ -359,7 +359,7 @@ fn combine_cookies(cookie1: &str, cookie2: &str) -> String { // Build the final cookie header string cookie_map .into_iter() - .map(|(key, value)| format!("{}={}", key, value)) + .map(|(key, value)| format!("{key}={value}")) .collect::>() .join("; ") } @@ -522,12 +522,32 @@ pub fn parse_request_file(config: &mut Configuration) -> Result<()> { let url = parse_url_with_raw_path(uri); - if url.is_err() { + if let Ok(mut url) = url { + if let Some(host) = config.headers.get("Host") { + url.set_host(Some(host)).unwrap(); + } + + url.query_pairs().for_each(|(key, value)| { + for (k, _) in &config.queries { + if k.to_lowercase() == key.to_lowercase() { + // allow cli options to take precedent when query names match + return; + } + } + + config.queries.push((key.to_string(), value.to_string())); + }); + + url.set_query(None); + url.set_fragment(None); + + config.target_url = url.to_string(); + } else { // uri in request line is not a valid URL, so it's most likely a path/relative url // we need to combine it with the host header for (key, value) in &config.headers { if key.to_lowercase() == "host" { - config.target_url = format!("{}{}", value, uri); + config.target_url = format!("{value}{uri}"); break; } } @@ -559,28 +579,6 @@ pub fn parse_request_file(config: &mut Configuration) -> Result<()> { config.queries.push((name, value)); }); } - } else { - let mut url = url.unwrap(); - - if let Some(host) = config.headers.get("Host") { - url.set_host(Some(host)).unwrap(); - } - - url.query_pairs().for_each(|(key, value)| { - for (k, _) in &config.queries { - if k.to_lowercase() == key.to_lowercase() { - // allow cli options to take precedent when query names match - return; - } - } - - config.queries.push((key.to_string(), value.to_string())); - }); - - url.set_query(None); - url.set_fragment(None); - - config.target_url = url.to_string(); } Ok(()) diff --git a/src/event_handlers/container.rs b/src/event_handlers/container.rs index aab6972..20a3636 100644 --- a/src/event_handlers/container.rs +++ b/src/event_handlers/container.rs @@ -112,7 +112,7 @@ impl Handles { pub fn set_scan_handle(&self, handle: ScanHandle) { if let Ok(mut guard) = self.scans.write() { if guard.is_none() { - let _ = std::mem::replace(&mut *guard, Some(handle)); + guard.replace(handle); } } } diff --git a/src/event_handlers/inputs.rs b/src/event_handlers/inputs.rs index 771849c..64fce83 100644 --- a/src/event_handlers/inputs.rs +++ b/src/event_handlers/inputs.rs @@ -117,7 +117,7 @@ impl TermInputHandler { let Ok(mut state_file) = open_file(&temp_filename.to_string_lossy()) else { // couldn't open the fallback file, let the user know - let error = format!("❌❌ Could not save {:?}, giving up...", temp_filename); + let error = format!("❌❌ Could not save {temp_filename:?}, giving up..."); PROGRESS_PRINTER.println(error); log::trace!("exit: sigint_handler (failed to write)"); @@ -126,7 +126,7 @@ impl TermInputHandler { write_to(&state, &mut state_file, true)?; - let msg = format!("✅ Saved scan state to {:?}", temp_filename); + let msg = format!("✅ Saved scan state to {temp_filename:?}"); PROGRESS_PRINTER.println(msg); log::trace!("exit: sigint_handler (saved to temp folder)"); diff --git a/src/event_handlers/outputs.rs b/src/event_handlers/outputs.rs index b9da00b..234b9ea 100644 --- a/src/event_handlers/outputs.rs +++ b/src/event_handlers/outputs.rs @@ -402,7 +402,7 @@ impl TermOutHandler { let url = response.url(); // confirmed safe: see src/response.rs for comments - let filename = url.path_segments().unwrap().last().unwrap(); + let filename = url.path_segments().unwrap().next_back().unwrap(); if !filename.is_empty() { // append rules @@ -501,7 +501,7 @@ mod tests { let paths: Vec<_> = urls .iter() - .map(|url| url.path_segments().unwrap().last().unwrap()) + .map(|url| url.path_segments().unwrap().next_back().unwrap()) .collect(); assert_eq!(urls.len(), 7); @@ -545,7 +545,7 @@ mod tests { let paths: Vec<_> = urls .iter() - .map(|url| url.path_segments().unwrap().last().unwrap()) + .map(|url| url.path_segments().unwrap().next_back().unwrap()) .collect(); assert_eq!(urls.len(), 6); diff --git a/src/event_handlers/scans.rs b/src/event_handlers/scans.rs index b3640ff..1dccd08 100644 --- a/src/event_handlers/scans.rs +++ b/src/event_handlers/scans.rs @@ -110,7 +110,7 @@ impl ScanHandler { fn wordlist(&self, wordlist: Arc>) { if let Ok(mut guard) = self.wordlist.lock() { if guard.is_none() { - let _ = std::mem::replace(&mut *guard, Some(wordlist)); + guard.replace(wordlist); } } } @@ -209,12 +209,12 @@ impl ScanHandler { /// /// updating all bar lengths correctly requires a few different actions on our part. /// - get the current number of requests expected per scan (dynamic when --collect-extensions - /// is used) + /// is used) /// - update the overall progress bar via the statistics handler (total expected) /// - update the expected per scan value tracked in the statistics handler /// - update progress bars on each FeroxScan (type::directory) that are running/not-started /// - update progress bar length on FeroxScans (this is used when creating new a FeroxScan and - /// determines the new scan's progress bar length) + /// determines the new scan's progress bar length) fn update_all_bar_lengths(&self) -> Result<()> { log::trace!("enter: update_all_bar_lengths"); diff --git a/src/filters/empty.rs b/src/filters/empty.rs index 90ae250..e68e9b4 100644 --- a/src/filters/empty.rs +++ b/src/filters/empty.rs @@ -12,7 +12,7 @@ impl FeroxFilter for EmptyFilter { /// Compare one EmptyFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/lines.rs b/src/filters/lines.rs index 2ca87a3..d12aaf9 100644 --- a/src/filters/lines.rs +++ b/src/filters/lines.rs @@ -23,7 +23,7 @@ impl FeroxFilter for LinesFilter { /// Compare one LinesFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/regex.rs b/src/filters/regex.rs index 0232c28..a465243 100644 --- a/src/filters/regex.rs +++ b/src/filters/regex.rs @@ -41,7 +41,7 @@ impl FeroxFilter for RegexFilter { /// Compare one SizeFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/similarity.rs b/src/filters/similarity.rs index 1b3013e..dc00874 100644 --- a/src/filters/similarity.rs +++ b/src/filters/similarity.rs @@ -39,7 +39,7 @@ impl FeroxFilter for SimilarityFilter { fn box_eq(&self, other: &dyn Any) -> bool { other .downcast_ref::() - .map_or(false, |a| self.hash == a.hash) + .is_some_and(|a| self.hash == a.hash) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/size.rs b/src/filters/size.rs index ba43d43..b809959 100644 --- a/src/filters/size.rs +++ b/src/filters/size.rs @@ -23,7 +23,7 @@ impl FeroxFilter for SizeFilter { /// Compare one SizeFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/status_code.rs b/src/filters/status_code.rs index 1e36f48..815f5f7 100644 --- a/src/filters/status_code.rs +++ b/src/filters/status_code.rs @@ -30,7 +30,7 @@ impl FeroxFilter for StatusCodeFilter { /// Compare one StatusCodeFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/filters/wildcard.rs b/src/filters/wildcard.rs index 7a54d16..e0a8789 100644 --- a/src/filters/wildcard.rs +++ b/src/filters/wildcard.rs @@ -144,7 +144,7 @@ impl FeroxFilter for WildcardFilter { /// Compare one WildcardFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes @@ -175,6 +175,6 @@ impl std::fmt::Display for WildcardFilter { ), OutputLevel::Default, ); - write!(f, "{}", msg) + write!(f, "{msg}") } } diff --git a/src/filters/words.rs b/src/filters/words.rs index 8731426..05050ee 100644 --- a/src/filters/words.rs +++ b/src/filters/words.rs @@ -23,7 +23,7 @@ impl FeroxFilter for WordsFilter { /// Compare one WordsFilter to another fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) + other.downcast_ref::() == Some(self) } /// Return self as Any for dynamic dispatch purposes diff --git a/src/heuristics.rs b/src/heuristics.rs index acd7880..ef0a47d 100644 --- a/src/heuristics.rs +++ b/src/heuristics.rs @@ -287,7 +287,7 @@ impl HeuristicTests { // and then we want to add any extensions that was specified // or has since been added to the running config for ext in &self.handles.config.extensions { - extensions.push(format!(".{}", ext)); + extensions.push(format!(".{ext}")); } // for every method, attempt to id its 404 response @@ -409,7 +409,7 @@ impl HeuristicTests { // if we're here, we've found a new wildcard that we didn't previously display, print it if print_sentry { - ferox_print(&format!("{}", new_wildcard), &PROGRESS_PRINTER); + ferox_print(&format!("{new_wildcard}"), &PROGRESS_PRINTER); } } } diff --git a/src/main.rs b/src/main.rs index ec2cddc..a1948d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -226,12 +226,12 @@ async fn wrapped_main(config: Arc) -> Result<()> { // check if update_app is true if config.update_app { match update_app().await { - Err(e) => eprintln!("\n[ERROR] {}", e), + Err(e) => eprintln!("\n[ERROR] {e}"), Ok(self_update::Status::UpToDate(version)) => { - eprintln!("\nFeroxbuster {} is up to date", version) + eprintln!("\nFeroxbuster {version} is up to date") } Ok(self_update::Status::Updated(version)) => { - eprintln!("\nFeroxbuster updated to {} version", version) + eprintln!("\nFeroxbuster updated to {version} version") } } exit(0); @@ -259,11 +259,11 @@ async fn wrapped_main(config: Arc) -> Result<()> { } // attempt to get the filename from the url's path - let Some(path_segments) = response.url().path_segments() else { + let Some(mut path_segments) = response.url().path_segments() else { bail!("Unable to parse path from url: {}", response.url()); }; - let Some(filename) = path_segments.last() else { + let Some(filename) = path_segments.next_back() else { bail!( "Unable to parse filename from url's path: {}", response.url().path() @@ -477,13 +477,14 @@ async fn wrapped_main(config: Arc) -> Result<()> { if n > 0 { let trimmed = buf.trim(); if !trimmed.is_empty() { - println!("{}", trimmed); + println!("{trimmed}"); } buf.clear(); } else { break; } } + let _ = output.wait(); drop(permit); }); } @@ -612,7 +613,7 @@ async fn clean_up(handles: Arc, tasks: Tasks) -> Result<()> { } async fn update_app() -> Result> { - let target_os = format!("{}-{}", ARCH, OS); + let target_os = format!("{ARCH}-{OS}"); let status = tokio::task::spawn_blocking(move || { self_update::backends::github::Update::configure() .repo_owner("epi052") diff --git a/src/response.rs b/src/response.rs index 39bfe4b..714ac8c 100644 --- a/src/response.rs +++ b/src/response.rs @@ -190,15 +190,14 @@ impl FeroxResponse { /// /// Additionally, inspects query parameters, as they're also often indicative of a file pub fn is_file(&self) -> bool { - let has_extension = match self.url.path_segments() { - Some(path) => { - if let Some(last) = path.last() { - last.contains('.') // last segment has some sort of extension, probably - } else { - false - } + let has_extension = if let Some(mut path) = self.url.path_segments() { + if let Some(last) = path.next_back() { + last.contains('.') // last segment has some sort of extension, probably + } else { + false } - None => false, + } else { + false }; self.url.query_pairs().count() > 0 || has_extension @@ -279,7 +278,7 @@ impl FeroxResponse { // (which may be empty). // // meaning: the two unwraps here are fine, the worst outcome is an empty string - let filename = self.url.path_segments().unwrap().last().unwrap(); + let filename = self.url.path_segments().unwrap().next_back().unwrap(); if !filename.is_empty() { // non-empty string, try to get extension diff --git a/src/scan_manager/scan.rs b/src/scan_manager/scan.rs index 20e7629..3725af6 100644 --- a/src/scan_manager/scan.rs +++ b/src/scan_manager/scan.rs @@ -198,7 +198,7 @@ impl FeroxScan { /// small wrapper to set the JoinHandle pub async fn set_task(&self, task: JoinHandle<()>) -> Result<()> { let mut guard = self.task.lock().await; - let _ = std::mem::replace(&mut *guard, Some(task)); + guard.replace(task); Ok(()) } @@ -260,7 +260,7 @@ impl FeroxScan { pb.set_position(self.requests_made_so_far); - let _ = std::mem::replace(&mut *guard, Some(pb.clone())); + guard.replace(pb.clone()); pb } diff --git a/src/scan_manager/scan_container.rs b/src/scan_manager/scan_container.rs index d2a078e..9413dfd 100644 --- a/src/scan_manager/scan_container.rs +++ b/src/scan_manager/scan_container.rs @@ -474,7 +474,10 @@ impl FeroxScans { self.menu.clear_screen(); - let banner = Banner::new(&[handles.config.target_url.clone()], &handles.config); + let banner = Banner::new( + std::slice::from_ref(&handles.config.target_url), + &handles.config, + ); banner .print_to(&self.menu.term, handles.config.clone()) .unwrap_or_default(); diff --git a/src/scan_manager/tests.rs b/src/scan_manager/tests.rs index 25f37ce..ea203c8 100644 --- a/src/scan_manager/tests.rs +++ b/src/scan_manager/tests.rs @@ -703,7 +703,7 @@ fn menu_get_command_input_from_user_returns_cancel() { let menu = Menu::new(); for (idx, cmd) in ["cancel", "Cancel", "c", "C"].iter().enumerate() { - let force = idx % 2 == 0; + let force = idx.is_multiple_of(2); let full_cmd = if force { format!("{cmd} -f {idx}\n") diff --git a/src/scanner/requester.rs b/src/scanner/requester.rs index 2fe0f30..f39a771 100644 --- a/src/scanner/requester.rs +++ b/src/scanner/requester.rs @@ -480,8 +480,9 @@ impl Requester { if let Ok(mut guard) = TF_IDF.write() { if let Some(doc) = Document::from_html(ferox_response.text()) { guard.add_document(doc); - if guard.num_documents() % 12 == 0 - || (guard.num_documents() < 5 && guard.num_documents() % 2 == 0) + if guard.num_documents().is_multiple_of(12) + || (guard.num_documents() < 5 + && guard.num_documents().is_multiple_of(2)) { guard.calculate_tf_idf_scores(); } diff --git a/src/traits.rs b/src/traits.rs index 77513c5..d2c4c07 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -50,32 +50,31 @@ impl Display for dyn FeroxFilter { unreachable!("wildcard filter without any filters set"); } (None, None, Some(lc)) => { - msg.push_str(&format!("containing {} lines", lc)); + msg.push_str(&format!("containing {lc} lines")); } (None, Some(wc), None) => { - msg.push_str(&format!("containing {} words", wc)); + msg.push_str(&format!("containing {wc} words")); } (None, Some(wc), Some(lc)) => { - msg.push_str(&format!("containing {} words and {} lines", wc, lc)); + msg.push_str(&format!("containing {wc} words and {lc} lines")); } (Some(cl), None, None) => { - msg.push_str(&format!("containing {} bytes", cl)); + msg.push_str(&format!("containing {cl} bytes")); } (Some(cl), None, Some(lc)) => { - msg.push_str(&format!("containing {} bytes and {} lines", cl, lc)); + msg.push_str(&format!("containing {cl} bytes and {lc} lines")); } (Some(cl), Some(wc), None) => { - msg.push_str(&format!("containing {} bytes and {} words", cl, wc)); + msg.push_str(&format!("containing {cl} bytes and {wc} words")); } (Some(cl), Some(wc), Some(lc)) => { msg.push_str(&format!( - "containing {} bytes, {} words, and {} lines", - cl, wc, lc + "containing {cl} bytes, {wc} words, and {lc} lines" )); } } - write!(f, "{}", msg) + write!(f, "{msg}") } else if let Some(filter) = self.as_any().downcast_ref::() { write!(f, "Status code: {}", style(filter.filter_code).cyan()) } else if let Some(filter) = self.as_any().downcast_ref::() { diff --git a/src/utils.rs b/src/utils.rs index b0cc7fc..ef9ccb9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -612,7 +612,7 @@ pub fn parse_url_with_raw_path(url: &str) -> Result { if let Some(port) = parsed.port() { // if the url has a port, then the farthest right authority component is // the port - farthest_right_authority_part = format!(":{}", port); + farthest_right_authority_part = format!(":{port}"); } else if parsed.has_host() { // if the url has a host, then the farthest right authority component is // the host diff --git a/tests/test_heuristics.rs b/tests/test_heuristics.rs index b8c7f15..bbc2af3 100644 --- a/tests/test_heuristics.rs +++ b/tests/test_heuristics.rs @@ -337,7 +337,7 @@ fn heuristics_wildcard_test_that_auto_filtering_403s_still_allows_for_recursion_ }); srv.mock(|when, then| { - when.method(GET).path(format!("/LICENSE/{}", super_long)); + when.method(GET).path(format!("/LICENSE/{super_long}")); then.status(200); }); diff --git a/tests/test_policies.rs b/tests/test_policies.rs index 9849d7d..0ebf753 100644 --- a/tests/test_policies.rs +++ b/tests/test_policies.rs @@ -75,6 +75,7 @@ fn auto_bail_cancels_scan_with_timeouts() { .success(); let debug_log = read_to_string(logfile).unwrap(); + let re = Regex::new("total_expected: ([0-9]+),").unwrap(); // read debug log to get the number of errors enforced for line in debug_log.lines() { @@ -83,7 +84,6 @@ fn auto_bail_cancels_scan_with_timeouts() { let str_msg = message.as_str().unwrap_or_default().to_string(); if str_msg.starts_with("Stats") { - let re = Regex::new("total_expected: ([0-9]+),").unwrap(); assert!(re.is_match(&str_msg)); let total_expected = re .captures(&str_msg) @@ -154,6 +154,7 @@ fn auto_bail_cancels_scan_with_403s() { println!("log filesize: {}", logfile.metadata().unwrap().len()); let debug_log = read_to_string(logfile).unwrap(); + let re = Regex::new("total_expected: ([0-9]+),").unwrap(); // read debug log to get the number of errors enforced for line in debug_log.lines() { @@ -163,7 +164,6 @@ fn auto_bail_cancels_scan_with_403s() { if str_msg.starts_with("Stats") { println!("{str_msg}"); - let re = Regex::new("total_expected: ([0-9]+),").unwrap(); assert!(re.is_match(&str_msg)); let total_expected = re .captures(&str_msg) @@ -236,6 +236,7 @@ fn auto_bail_cancels_scan_with_429s() { println!("log filesize: {}", logfile.metadata().unwrap().len()); let debug_log = read_to_string(logfile).unwrap(); + let re = Regex::new("total_expected: ([0-9]+),").unwrap(); // read debug log to get the number of errors enforced for line in debug_log.lines() { @@ -245,7 +246,6 @@ fn auto_bail_cancels_scan_with_429s() { if str_msg.starts_with("Stats") { println!("{str_msg}"); - let re = Regex::new("total_expected: ([0-9]+),").unwrap(); assert!(re.is_match(&str_msg)); let total_expected = re .captures(&str_msg)