Initial Commit

This commit is contained in:
2026-09-23 09:16:09 -04:00
commit 0cd2a516bb
49 changed files with 10134 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
use std::process::Stdio;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use serde::Deserialize;
use tauri::{AppHandle, Emitter};
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::process::Command;
static NMAP_CANCEL: std::sync::OnceLock<Arc<AtomicBool>> = std::sync::OnceLock::new();
fn get_nmap_cancel() -> Arc<AtomicBool> {
NMAP_CANCEL
.get_or_init(|| Arc::new(AtomicBool::new(false)))
.clone()
}
#[derive(Debug, Deserialize)]
pub struct NmapConfig {
pub target: String,
pub args: Vec<String>,
}
#[tauri::command]
pub async fn run_nmap(app: AppHandle, config: NmapConfig) -> Result<(), String> {
// Check nmap exists
let check = Command::new("nmap")
.arg("--version")
.output()
.await
.map_err(|_| "nmap not found. Please install nmap.".to_string())?;
if !check.status.success() {
return Err("nmap not found. Please install nmap.".to_string());
}
let cancel = get_nmap_cancel();
cancel.store(false, Ordering::Relaxed);
let _ = app.emit("nmap:start", &config.target);
let mut cmd = Command::new("nmap");
for arg in &config.args {
cmd.arg(arg);
}
for target in config.target.split_whitespace() {
cmd.arg(target);
}
cmd.stdout(Stdio::piped());
cmd.stderr(Stdio::piped());
let mut child = cmd
.spawn()
.map_err(|e| format!("Failed to start nmap: {}", e))?;
let stdout = child
.stdout
.take()
.ok_or_else(|| "Failed to capture nmap stdout".to_string())?;
let stderr = child
.stderr
.take()
.ok_or_else(|| "Failed to capture nmap stderr".to_string())?;
// Stream stdout
let app2 = app.clone();
let cancel2 = cancel.clone();
let stdout_handle = tokio::spawn(async move {
let mut reader = BufReader::new(stdout).lines();
while let Ok(Some(line)) = reader.next_line().await {
if cancel2.load(Ordering::Relaxed) {
break;
}
let _ = app2.emit("nmap:line", &line);
}
});
// Stream stderr
let app3 = app.clone();
let stderr_handle = tokio::spawn(async move {
let mut reader = BufReader::new(stderr).lines();
while let Ok(Some(line)) = reader.next_line().await {
let _ = app3.emit("nmap:line", &line);
}
});
// Wait for completion or cancellation
tokio::select! {
status = child.wait() => {
match status {
Ok(s) if s.success() => {
let _ = app.emit("nmap:complete", "Scan complete");
}
Ok(s) => {
let _ = app.emit("nmap:complete",
format!("nmap exited with code {}", s.code().unwrap_or(-1)));
}
Err(e) => {
let _ = app.emit("nmap:error", format!("nmap error: {}", e));
}
}
}
_ = async {
loop {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
if cancel.load(Ordering::Relaxed) {
break;
}
}
} => {
let _ = child.kill().await;
let _ = app.emit("nmap:complete", "Scan cancelled");
}
}
let _ = stdout_handle.await;
let _ = stderr_handle.await;
Ok(())
}
#[tauri::command]
pub async fn stop_nmap() -> Result<(), String> {
let cancel = get_nmap_cancel();
cancel.store(true, Ordering::Relaxed);
tracing::info!("Nmap scan cancelled");
Ok(())
}