use microsandbox_utils::SupportedPathType;
use crate::{MicrosandboxError, MicrosandboxResult};
pub fn paths_overlap(path1: &str, path2: &str) -> bool {
let path1 = if path1.ends_with('/') {
path1.to_string()
} else {
format!("{}/", path1)
};
let path2 = if path2.ends_with('/') {
path2.to_string()
} else {
format!("{}/", path2)
};
path1.starts_with(&path2) || path2.starts_with(&path1)
}
pub fn normalize_volume_path(base_path: &str, requested_path: &str) -> MicrosandboxResult<String> {
let normalized_base =
microsandbox_utils::normalize_path(base_path, SupportedPathType::Absolute)?;
if requested_path.starts_with('/') {
let normalized_requested =
microsandbox_utils::normalize_path(requested_path, SupportedPathType::Absolute)?;
if !normalized_requested.starts_with(&normalized_base) {
return Err(MicrosandboxError::PathValidation(format!(
"Absolute path '{}' must be under base path '{}'",
normalized_requested, normalized_base
)));
}
Ok(normalized_requested)
} else {
let normalized_requested =
microsandbox_utils::normalize_path(requested_path, SupportedPathType::Relative)?;
let full_path = format!("{}/{}", normalized_base, normalized_requested);
microsandbox_utils::normalize_path(&full_path, SupportedPathType::Absolute)
.map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_paths_overlap() {
assert!(paths_overlap("/data", "/data"));
assert!(paths_overlap("/data", "/data/app"));
assert!(paths_overlap("/data/app", "/data"));
assert!(paths_overlap("/data/app/logs", "/data/app"));
assert!(!paths_overlap("/data", "/database"));
assert!(!paths_overlap("/var/log", "/var/lib"));
assert!(!paths_overlap("/data/app1", "/data/app2"));
assert!(!paths_overlap("/data/app/logs", "/data/web/logs"));
}
}