subscan 1.3.0

A subdomain enumeration tool leveraging diverse techniques, designed for advanced pentesting operations
Documentation
use std::{
    fs::{self, File},
    io::Write,
    path::PathBuf,
};

use tempfile::{tempdir_in, TempDir};
use tokio::sync::OnceCell;

use super::utils::{get_random_port, stubs_path};

pub struct StubTemplateManager<'a> {
    pub temp: TempDir,
    pub stubs: PathBuf,
    pub templates: Vec<&'a str>,
    pub port: u16,
    pub init: OnceCell<()>,
}

impl<'a> From<(&'a str, Vec<&'a str>)> for StubTemplateManager<'a> {
    fn from(tuple: (&'a str, Vec<&'a str>)) -> Self {
        Self::new(tuple.0, tuple.1)
    }
}

impl<'a> StubTemplateManager<'a> {
    pub fn new(stubs: &'a str, templates: Vec<&'a str>) -> Self {
        let stubs = stubs_path().join(stubs);
        let temp = tempdir_in(stubs.clone()).unwrap();
        let port = get_random_port();
        let init = OnceCell::new();

        Self {
            temp,
            stubs,
            templates,
            port,
            init,
        }
    }

    pub async fn port(&self) -> u16 {
        self.init().await;
        self.port
    }

    pub async fn temp(&self) -> &str {
        self.init().await;
        self.temp.path().to_str().unwrap()
    }

    async fn init(&self) {
        let init = || async {
            for entry in self.stubs.read_dir().unwrap().flatten() {
                if entry.path().is_file() {
                    let name = entry.file_name();
                    let target_path = self.temp.path().join(&name);

                    if self.templates.contains(&name.to_str().unwrap()) {
                        self.fill_port(entry.path(), target_path).await;
                    } else {
                        fs::copy(entry.path(), target_path).unwrap();
                    }
                }
            }
        };

        self.init.get_or_init(init).await;
    }

    async fn fill_port(&self, input: PathBuf, output: PathBuf) {
        let template = fs::read_to_string(input).unwrap();
        let filled_stub = template.replace("{{port}}", &self.port.to_string());
        let mut temp_stub = File::create(output).unwrap();

        temp_stub.write_all(filled_stub.as_bytes()).unwrap();
    }
}