Skip to main content

aurora_modules/
crypto.rs

1use aurora_core::{AuroraResult, Pipeline, Value, AuroraError};
2use std::process::Command;
3use std::collections::hash_map::DefaultHasher;
4use std::hash::{Hash, Hasher};
5use std::io::Write;
6
7fn find_tool(name: &str) -> bool {
8    Command::new("which")
9        .arg(name)
10        .output()
11        .ok()
12        .is_some_and(|o| o.status.success())
13}
14
15pub fn crypto_hash(input: &str, algo: Option<&str>) -> AuroraResult<Pipeline> {
16    let algo_name = algo.unwrap_or("sha256");
17    let is_file = std::path::Path::new(input).exists() && std::path::Path::new(input).is_file();
18
19    match algo_name {
20        "sha256" => {
21            if is_file && find_tool("sha256sum") {
22                hash_file_cmd("sha256sum", input, "sha256")
23            } else if is_file && find_tool("shasum") {
24                hash_file_cmd("shasum", input, "sha256")
25            } else {
26                hash_string_cmd("sha256sum", input, "sha256")
27            }
28        }
29        "md5" => {
30            if is_file && find_tool("md5sum") {
31                hash_file_cmd("md5sum", input, "md5")
32            } else if find_tool("md5sum") {
33                hash_string_cmd("md5sum", input, "md5")
34            } else if find_tool("shasum") {
35                hash_string_cmd("shasum", input, "md5")
36            } else {
37                return Err(AuroraError::ModuleError(
38                    "md5 requires md5sum or shasum command".into()
39                ));
40            }
41        }
42        _ => {
43            if find_tool(algo_name) {
44                hash_string_cmd(algo_name, input, algo_name)
45            } else {
46                return Err(AuroraError::InvalidInput(
47                    format!("unknown algorithm: {algo_name}")
48                ));
49            }
50        }
51    }
52}
53
54fn hash_file_cmd(tool: &str, path: &str, algo: &str) -> AuroraResult<Pipeline> {
55    let output = Command::new(tool)
56        .arg(path)
57        .output()
58        .map_err(|e| AuroraError::ModuleError(format!("{tool} failed: {e}")))?;
59
60    let stdout = String::from_utf8_lossy(&output.stdout);
61    let hash = stdout.split_whitespace().next().unwrap_or("").to_string();
62
63    Ok(Pipeline::table(
64        vec!["algorithm".into(), "hash".into()],
65        vec![vec![Value::String(algo.into()), Value::String(hash)]],
66    ))
67}
68
69fn hash_string_cmd(tool: &str, input: &str, algo: &str) -> AuroraResult<Pipeline> {
70    let mut child = Command::new(tool)
71        .stdin(std::process::Stdio::piped())
72        .stdout(std::process::Stdio::piped())
73        .stderr(std::process::Stdio::null())
74        .spawn()
75        .map_err(|e| AuroraError::ModuleError(format!("{tool} failed: {e}")))?;
76
77    if let Some(ref mut stdin) = child.stdin {
78        stdin.write_all(input.as_bytes())
79            .map_err(|e| AuroraError::ModuleError(format!("Write failed: {e}")))?;
80    }
81    drop(child.stdin.take());
82
83    let output = child.wait_with_output()
84        .map_err(|e| AuroraError::ModuleError(format!("{tool} failed: {e}")))?;
85    let hash = String::from_utf8_lossy(&output.stdout)
86        .split_whitespace()
87        .next()
88        .unwrap_or("")
89        .to_string();
90
91    Ok(Pipeline::table(
92        vec!["algorithm".into(), "hash".into()],
93        vec![vec![Value::String(algo.into()), Value::String(hash)]],
94    ))
95}
96
97pub fn crypto_genkey(algo: Option<&str>) -> AuroraResult<Pipeline> {
98    let algo_name = algo.unwrap_or("aes-256");
99    use std::time::{SystemTime, UNIX_EPOCH};
100
101    let seed = SystemTime::now()
102        .duration_since(UNIX_EPOCH)
103        .map(|d| d.as_nanos())
104        .unwrap_or(0);
105
106    let mut hasher = DefaultHasher::new();
107    seed.hash(&mut hasher);
108    let hash = hasher.finish();
109
110    let key = format!("{:016x}{:016x}", hash, hash);
111
112    Ok(Pipeline::table(
113        vec!["algorithm".into(), "key".into()],
114        vec![vec![Value::String(algo_name.into()), Value::String(key)]],
115    ))
116}