Added tests and better path validation

Secure video endpoints.
This commit is contained in:
Cameron Cordes
2020-07-23 14:14:40 -04:00
parent f63dd9cb05
commit 68bb9d9d5c
2 changed files with 108 additions and 22 deletions

View File

@@ -30,7 +30,109 @@ fn is_image_or_video(path: &Path) -> bool {
extension == "png"
|| extension == "jpg"
|| extension == "jpeg"
|| extension == "rs"
|| extension == "mp4"
|| extension == "mov"
}
pub fn is_valid_path(path: &str) -> Option<PathBuf> {
let base = PathBuf::from(dotenv::var("BASE_PATH").unwrap());
is_valid_full_path(&base, path)
}
fn is_valid_full_path(base: &Path, path: &str) -> Option<PathBuf> {
let path = PathBuf::from(path);
if path.is_relative() {
let mut full_path = PathBuf::from(base);
full_path.push(&path);
full_path
.canonicalize()
.and_then(|p| {
if p.starts_with(base) {
Ok(p)
} else {
Err(io::Error::new(
io::ErrorKind::Other,
"Path below base directory",
))
}
})
.ok()
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
use std::fs::{create_dir_all, File};
#[test]
fn directory_traversal_test() {
assert_eq!(None, is_valid_path("../"));
assert_eq!(None, is_valid_path(".."));
assert_eq!(None, is_valid_path("fake/../../../"));
assert_eq!(None, is_valid_path("../../../etc/passwd"));
assert_eq!(None, is_valid_path("..//etc/passwd"));
assert_eq!(None, is_valid_path("..%2f..%2f/etc/passwd"));
assert_eq!(None, is_valid_path("%2e%2e%2f%2e%2e%2f/etc/passwd"));
assert_eq!(None, is_valid_path("\\\\attacker.com\\shared\\mal.php"));
}
#[test]
fn build_from_relative_path_test() {
let base = env::temp_dir();
let mut test_file = PathBuf::from(&base);
test_file.push("test.png");
File::create(test_file).unwrap();
assert!(is_valid_full_path(&base, "test.png").is_some());
let path = "relative/path/test.png";
let mut test_file = PathBuf::from(&base);
test_file.push(path);
create_dir_all(test_file.parent().unwrap()).unwrap();
File::create(test_file).unwrap();
assert_eq!(
Some(PathBuf::from("/tmp/relative/path/test.png")),
is_valid_full_path(&base, path)
);
}
#[test]
fn png_valid_extension_test() {
assert!(is_image_or_video(Path::new("image.png")));
assert!(is_image_or_video(Path::new("image.PNG")));
assert!(is_image_or_video(Path::new("image.pNg")));
}
#[test]
fn jpg_valid_extension_test() {
assert!(is_image_or_video(Path::new("image.jpeg")));
assert!(is_image_or_video(Path::new("image.JPEG")));
assert!(is_image_or_video(Path::new("image.jpg")));
assert!(is_image_or_video(Path::new("image.JPG")));
}
#[test]
fn mp4_valid_extension_test() {
assert!(is_image_or_video(Path::new("image.mp4")));
assert!(is_image_or_video(Path::new("image.mP4")));
assert!(is_image_or_video(Path::new("image.MP4")));
}
#[test]
fn mov_valid_extension_test() {
assert!(is_image_or_video(Path::new("image.mov")));
assert!(is_image_or_video(Path::new("image.MOV")));
assert!(is_image_or_video(Path::new("image.MoV")));
}
#[test]
fn hidden_file_not_valid_test() {
assert!(!is_image_or_video(Path::new(".DS_store")));
}
}