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