safe_find/
lib.rs

1use std::collections::HashSet;
2use std::process::{Command, ExitStatus};
3
4/// Dangerous options for the find command
5pub const FIND_DANGEROUS_OPTIONS: &[&str] = &[
6    "-exec", "-execdir", "-ok", "-okdir", "-delete",
7];
8
9/// Dangerous options for the fd command  
10pub const FD_DANGEROUS_OPTIONS: &[&str] = &[
11    "-x", "--exec", "-X", "--exec-batch", "-l", "--list-details",
12];
13
14/// Check if any dangerous options are present in the arguments
15pub fn check_dangerous_options(args: &[String], dangerous_options: &[&str]) -> Result<(), String> {
16    let dangerous_set: HashSet<&str> = dangerous_options.iter().copied().collect();
17    
18    for arg in args {
19        if dangerous_set.contains(arg.as_str()) {
20            return Err(format!(
21                "Error: Dangerous option '{}' is not allowed for security reasons",
22                arg
23            ));
24        }
25    }
26    
27    Ok(())
28}
29
30/// Execute a command with the given arguments
31pub fn execute_command(command_name: &str, args: &[String]) -> Result<ExitStatus, std::io::Error> {
32    let mut cmd = Command::new(command_name);
33    cmd.args(args);
34    cmd.status()
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn test_check_dangerous_options_find() {
43        let safe_args = vec![".", "-name", "*.txt", "-type", "f"]
44            .into_iter()
45            .map(String::from)
46            .collect::<Vec<_>>();
47        assert!(check_dangerous_options(&safe_args, FIND_DANGEROUS_OPTIONS).is_ok());
48
49        let dangerous_args = vec![".", "-name", "*.txt", "-exec", "rm", "{}", ";"]
50            .into_iter()
51            .map(String::from)
52            .collect::<Vec<_>>();
53        assert!(check_dangerous_options(&dangerous_args, FIND_DANGEROUS_OPTIONS).is_err());
54    }
55
56    #[test]
57    fn test_check_dangerous_options_fd() {
58        let safe_args = vec!["*.js", "--type", "f"]
59            .into_iter()
60            .map(String::from)
61            .collect::<Vec<_>>();
62        assert!(check_dangerous_options(&safe_args, FD_DANGEROUS_OPTIONS).is_ok());
63
64        let dangerous_args = vec!["*.js", "-x", "rm"]
65            .into_iter()
66            .map(String::from)
67            .collect::<Vec<_>>();
68        assert!(check_dangerous_options(&dangerous_args, FD_DANGEROUS_OPTIONS).is_err());
69    }
70}