use super::*;
use crate::types::*;
use regex::Regex;
use serde::Serialize;
use std::fs::File;
use std::io::Write;
use std::process::Command;
#[derive(Debug, Serialize)]
struct Report {
pub access_points: Vec<AP>,
pub unlinked_clients: Vec<Client>,
}
#[derive(thiserror::Error, Debug)]
pub enum CapError {
#[error("Input/Output error: {0}")]
IoError(#[from] std::io::Error),
#[error("Regex error: {0}")]
BadRegex(#[from] regex::Error),
#[error("Json error: {0}")]
JsonError(#[from] serde_json::Error),
}
pub fn update_handshakes() -> Result<(), CapError> {
let handshakes = get_handshakes([
&(get_live_scan_path() + get_cap_ext()),
&(get_old_scan_path() + get_cap_ext()),
])?;
let mut aps = get_aps();
for (bssid, _) in handshakes {
if let Some(ap) = aps.get_mut(&bssid) {
ap.handshake = true;
}
}
log::trace!("handshakes updated");
Ok(())
}
pub fn get_handshakes<I, S>(args: I) -> Result<Vec<(String, String)>, CapError>
where
I: IntoIterator<Item = S>,
S: AsRef<std::ffi::OsStr>,
{
let capture_output = Command::new("aircrack-ng").args(args).output()?;
let output = String::from_utf8_lossy(&capture_output.stdout).to_string();
let re = Regex::new(r"\s+(\d+)\s+([\w:]+)\s+(.*)\s+WPA \((\d+)\s+handshake.*\)")?;
let mut handshakes = vec![];
for line in output.lines() {
let caps = match re.captures(line) {
Some(caps) => caps,
None => continue,
};
let bssid = caps[2].to_string();
let essid = caps[3].trim().to_string();
let handshake_count = caps[4].to_string();
if handshake_count.parse::<i32>().unwrap_or(0) > 0 {
handshakes.push((
bssid,
match essid.is_empty() {
true => "hidden".to_string(),
false => essid,
},
));
}
}
Ok(handshakes)
}
pub fn save_capture(path: &str) -> Result<(), CapError> {
std::fs::copy(get_old_scan_path() + get_cap_ext(), path)?;
log::info!("capture saved to '{}'", path);
Ok(())
}
pub fn save_report(path: &str) -> Result<(), CapError> {
let access_points = get_aps().values().cloned().collect::<Vec<AP>>();
let unlinked_clients = get_unlinked_clients()
.values()
.cloned()
.collect::<Vec<Client>>();
let report = Report {
access_points,
unlinked_clients,
};
let json_data = serde_json::to_string::<Report>(&report)?;
let mut file = File::create(path)?;
file.write_all(json_data.as_bytes())?;
log::info!("report saved to '{}'", path);
Ok(())
}