use std::fs;
use docgen_server::{resolve_doc_path, PathGuardError};
#[test]
fn rejects_all_traversal_vectors() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let docs = root.join("docs");
fs::create_dir_all(docs.join("guide")).unwrap();
fs::write(docs.join("ok.md"), "# ok\n").unwrap();
fs::write(docs.join("guide/intro.md"), "# intro\n").unwrap();
fs::write(root.join("secret.md"), "secret\n").unwrap();
let docs = docs.canonicalize().unwrap();
let ok = resolve_doc_path(&docs, "guide/intro.md").unwrap();
assert!(ok.starts_with(&docs));
assert!(ok.ends_with("guide/intro.md"));
resolve_doc_path(&docs, "./ok.md").unwrap();
assert_eq!(
resolve_doc_path(&docs, "../secret.md"),
Err(PathGuardError::Traversal)
);
assert_eq!(
resolve_doc_path(&docs, "../../etc/passwd"),
Err(PathGuardError::Traversal)
);
assert_eq!(
resolve_doc_path(&docs, "/etc/passwd"),
Err(PathGuardError::Absolute)
);
let abs = docs.join("ok.md");
assert_eq!(
resolve_doc_path(&docs, abs.to_str().unwrap()),
Err(PathGuardError::Absolute)
);
assert_eq!(
resolve_doc_path(&docs, "guide\\..\\..\\x.md"),
Err(PathGuardError::Traversal)
);
assert_eq!(
resolve_doc_path(&docs, "ok.txt"),
Err(PathGuardError::NotMarkdown)
);
assert_eq!(
resolve_doc_path(&docs, "nope.md"),
Err(PathGuardError::NotFound)
);
fs::create_dir_all(docs.join("adir.md")).unwrap();
assert_eq!(
resolve_doc_path(&docs, "adir.md"),
Err(PathGuardError::NotAFile)
);
#[cfg(unix)]
{
std::os::unix::fs::symlink(root.join("secret.md"), docs.join("escape.md")).unwrap();
assert_eq!(
resolve_doc_path(&docs, "escape.md"),
Err(PathGuardError::Traversal)
);
}
}