use anyhow::{Result, bail};
pub fn normalize_member_path(member_path: &str) -> String {
member_path.replace('/', "-")
}
pub fn needs_normalization(member_path: &str) -> bool {
member_path.contains('/')
}
pub fn validate_member_path(member_path: &str) -> Result<()> {
if member_path.is_empty() {
bail!("Invalid member path: empty path not allowed");
}
if member_path.starts_with('/') || member_path.starts_with('\\') {
bail!(
"Invalid member path '{}': absolute paths not allowed",
member_path
);
}
if member_path.len() > 2 && member_path.chars().nth(1) == Some(':') {
bail!(
"Invalid member path '{}': absolute paths not allowed",
member_path
);
}
if member_path.contains("..") {
bail!(
"Invalid member path '{}': path traversal not allowed",
member_path
);
}
if member_path.contains('\\') {
bail!(
"Invalid member path '{}': backslashes not allowed",
member_path
);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_member_path() {
assert_eq!(normalize_member_path("crates/rmcp"), "crates-rmcp");
assert_eq!(
normalize_member_path("crates/rmcp/submodule"),
"crates-rmcp-submodule"
);
assert_eq!(normalize_member_path("simple"), "simple");
assert_eq!(normalize_member_path("already-dashed"), "already-dashed");
}
#[test]
fn test_needs_normalization() {
assert!(needs_normalization("crates/rmcp"));
assert!(needs_normalization("path/to/member"));
assert!(!needs_normalization("simple"));
assert!(!needs_normalization("already-dashed"));
}
#[test]
fn test_validate_member_path() {
assert!(validate_member_path("crates/rmcp").is_ok());
assert!(validate_member_path("simple").is_ok());
assert!(validate_member_path("path/to/member").is_ok());
assert!(validate_member_path("").is_err());
assert!(validate_member_path("/absolute/path").is_err());
assert!(validate_member_path("\\windows\\path").is_err());
assert!(validate_member_path("C:\\Windows").is_err());
assert!(validate_member_path("../parent").is_err());
assert!(validate_member_path("path/../traversal").is_err());
assert!(validate_member_path("path\\with\\backslash").is_err());
}
}