pub mod analyzer;
pub mod patterns;
use crate::types::*;
use anyhow::Result;
use std::path::Path;
pub use analyzer::Analyzer;
pub fn analyze<P: AsRef<Path>>(target: P) -> Result<XRayReport> {
let analyzer = Analyzer::new(target.as_ref())?;
analyzer.analyze()
}
pub fn analyze_verbose<P: AsRef<Path>>(target: P) -> Result<XRayReport> {
let analyzer = Analyzer::new_verbose(target.as_ref())?;
let report = analyzer.analyze()?;
println!("X-Ray Analysis Complete");
println!(" Language: {:?}", report.language);
println!(" Frameworks: {:?}", report.frameworks);
println!(" Weak Points: {}", report.weak_points.len());
println!(" Recommended Attacks: {:?}", report.recommended_attacks);
if !report.file_statistics.is_empty() {
println!("\n Per-file Breakdown (top 10 by risk):");
let mut scored: Vec<_> = report
.file_statistics
.iter()
.map(|fs| {
let risk = fs.unsafe_blocks * 3
+ fs.panic_sites * 2
+ fs.unwrap_calls
+ fs.threading_constructs * 2;
(risk, fs)
})
.collect();
scored.sort_by(|a, b| b.0.cmp(&a.0));
for (rank, (risk, fs)) in scored.iter().take(10).enumerate() {
println!(
" {}. {} (risk: {}, lines: {}, unsafe: {}, panics: {}, \
unwraps: {}, alloc: {}, io: {}, threads: {})",
rank + 1,
fs.file_path,
risk,
fs.lines,
fs.unsafe_blocks,
fs.panic_sites,
fs.unwrap_calls,
fs.allocation_sites,
fs.io_operations,
fs.threading_constructs,
);
}
if scored.len() > 10 {
println!(" ... and {} more files", scored.len() - 10);
}
}
Ok(report)
}