elizaos_plugin_code/
path_utils.rs1use std::path::{Path, PathBuf};
2
3pub const DEFAULT_FORBIDDEN_COMMANDS: [&str; 5] =
4 ["rm -rf /", "rm -rf ~", "sudo rm", "mkfs", "dd if=/dev"];
5
6pub fn extract_base_command(command: &str) -> String {
7 command.split_whitespace().next().unwrap_or("").to_string()
8}
9
10pub fn is_safe_command(command: &str) -> bool {
11 let c = command.trim();
12 if c.is_empty() {
13 return false;
14 }
15 if c.starts_with("cd ") && c.contains("..") {
17 return false;
18 }
19 if c.contains("&&") || c.contains("||") || c.contains(';') {
20 return false;
21 }
22 if c.contains("$(") || c.contains('`') {
23 return false;
24 }
25 true
26}
27
28pub fn is_forbidden_command(command: &str, additional_forbidden: &[String]) -> bool {
29 let lower = command.to_lowercase();
30 for f in DEFAULT_FORBIDDEN_COMMANDS {
31 if lower.contains(&f.to_lowercase()) {
32 return true;
33 }
34 }
35 for f in additional_forbidden {
36 let ft = f.trim();
37 if ft.is_empty() {
38 continue;
39 }
40 if lower.contains(&ft.to_lowercase()) {
41 return true;
42 }
43 }
44 false
45}
46
47pub fn validate_path(
48 target_path: &str,
49 allowed_directory: &Path,
50 current_directory: &Path,
51) -> Option<PathBuf> {
52 let base = if current_directory.as_os_str().is_empty() {
53 allowed_directory
54 } else {
55 current_directory
56 };
57 let resolved = base.join(target_path);
58
59 let allowed = allowed_directory
61 .canonicalize()
62 .ok()
63 .unwrap_or_else(|| allowed_directory.to_path_buf());
64
65 let canonical = match resolved.canonicalize() {
67 Ok(p) => p,
68 Err(_) => {
69 let parent = resolved.parent()?.canonicalize().ok()?;
70 let name = resolved.file_name()?;
71 parent.join(name)
72 }
73 };
74
75 if canonical == allowed {
77 return Some(canonical);
78 }
79 canonical.strip_prefix(&allowed).ok()?;
80 Some(canonical)
81}