tryaudex_core/
validate.rs1use crate::error::{AvError, Result};
2
3pub fn session_id(id: &str) -> Result<()> {
10 if id.is_empty() || id.len() > 64 {
11 return Err(AvError::SessionNotFound { id: id.to_string() });
12 }
13 if !id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') {
14 return Err(AvError::SessionNotFound { id: id.to_string() });
15 }
16 Ok(())
17}
18
19pub fn path_component(s: &str, label: &str) -> Result<()> {
24 if s.is_empty() || s.contains('/') || s.contains('\\') || s.contains("..") {
25 return Err(AvError::InvalidPolicy(format!(
26 "Invalid {}: contains path traversal characters",
27 label
28 )));
29 }
30 Ok(())
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn valid_uuid_session_id() {
39 assert!(session_id("a1b2c3d4-e5f6-7890-abcd-ef1234567890").is_ok());
40 }
41
42 #[test]
43 fn valid_short_prefix() {
44 assert!(session_id("a1b2c3d4").is_ok());
45 }
46
47 #[test]
48 fn rejects_path_traversal() {
49 assert!(session_id("../../etc/passwd").is_err());
50 }
51
52 #[test]
53 fn rejects_slashes() {
54 assert!(session_id("foo/bar").is_err());
55 }
56
57 #[test]
58 fn rejects_empty() {
59 assert!(session_id("").is_err());
60 }
61
62 #[test]
63 fn rejects_shell_metacharacters() {
64 assert!(session_id("$(whoami)").is_err());
65 assert!(session_id("id;rm -rf /").is_err());
66 }
67
68 #[test]
69 fn path_component_valid() {
70 assert!(path_component("my-mount", "mount").is_ok());
71 assert!(path_component("my_role", "role").is_ok());
72 }
73
74 #[test]
75 fn path_component_rejects_traversal() {
76 assert!(path_component("../../sys/seal", "role").is_err());
77 assert!(path_component("foo/bar", "mount").is_err());
78 assert!(path_component("", "mount").is_err());
79 }
80}