aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJikstra <34889164+Jikstra@users.noreply.github.com>2021-09-10 13:56:31 +0000
committerGitHub <noreply@github.com>2021-09-10 13:56:31 +0000
commitd0cd4f0f21210cae8677941f6ca4059365767879 (patch)
tree623b58e978ef1c31c11553a5b077f51432a34f84 /tests
parentApply requested changes (diff)
parentMerge pull request #598 from svenstaro/dependabot/cargo/sha2-0.9.8 (diff)
downloadminiserve-d0cd4f0f21210cae8677941f6ca4059365767879.tar.gz
miniserve-d0cd4f0f21210cae8677941f6ca4059365767879.zip
Merge branch 'master' into feat_raw_mode
Diffstat (limited to 'tests')
-rw-r--r--tests/upload_files.rs91
1 files changed, 90 insertions, 1 deletions
diff --git a/tests/upload_files.rs b/tests/upload_files.rs
index 698eb46..5e764ba 100644
--- a/tests/upload_files.rs
+++ b/tests/upload_files.rs
@@ -1,6 +1,7 @@
mod fixtures;
-use fixtures::{server, Error, TestServer};
+use assert_fs::fixture::TempDir;
+use fixtures::{server, server_no_stderr, tmpdir, Error, TestServer};
use reqwest::blocking::{multipart, Client};
use rstest::rstest;
use select::document::Document;
@@ -78,3 +79,91 @@ fn uploading_files_is_prevented(server: TestServer) -> Result<(), Error> {
Ok(())
}
+
+/// Test for path traversal vulnerability (CWE-22) in both path parameter of query string and in
+/// file name (Content-Disposition)
+///
+/// see: https://github.com/svenstaro/miniserve/issues/518
+#[rstest]
+#[case("foo", "bar", "foo/bar")]
+#[case("/../foo", "bar", "foo/bar")]
+#[case("/foo", "/../bar", "foo/bar")]
+#[case("C:/foo", "C:/bar", if cfg!(windows) { "foo/bar" } else { "C:/foo/C:/bar" })]
+#[case(r"C:\foo", r"C:\bar", if cfg!(windows) { "foo/bar" } else { r"C:\foo/C:\bar" })]
+#[case(r"\foo", r"\..\bar", if cfg!(windows) { "foo/bar" } else { r"\foo/\..\bar" })]
+fn prevent_path_traversal_attacks(
+ #[with(&["-u"])] server: TestServer,
+ #[case] path: &str,
+ #[case] filename: &'static str,
+ #[case] expected: &str,
+) -> Result<(), Error> {
+ // Create test directories
+ use std::fs::create_dir_all;
+ create_dir_all(server.path().join("foo")).unwrap();
+ if !cfg!(windows) {
+ for dir in &["C:/foo/C:", r"C:\foo", r"\foo"] {
+ create_dir_all(server.path().join(dir)).expect(&format!("failed to create: {:?}", dir));
+ }
+ }
+
+ let expected_path = server.path().join(expected);
+ assert!(!expected_path.exists());
+
+ // Perform the actual upload.
+ let part = multipart::Part::text("this should be uploaded")
+ .file_name(filename)
+ .mime_str("text/plain")?;
+ let form = multipart::Form::new().part("file_to_upload", part);
+
+ Client::new()
+ .post(server.url().join(&format!("/upload?path={}", path))?)
+ .multipart(form)
+ .send()?
+ .error_for_status()?;
+
+ // Make sure that the file was uploaded to the expected path
+ assert!(expected_path.exists());
+
+ Ok(())
+}
+
+/// Test uploading to symlink directories that point outside the server root.
+/// See https://github.com/svenstaro/miniserve/issues/466
+#[rstest]
+#[case(server(&["-u"]), true)]
+#[case(server_no_stderr(&["-u", "--no-symlinks"]), false)]
+fn upload_to_symlink_directory(
+ #[case] server: TestServer,
+ #[case] ok: bool,
+ tmpdir: TempDir,
+) -> Result<(), Error> {
+ #[cfg(unix)]
+ use std::os::unix::fs::symlink as symlink_dir;
+ #[cfg(windows)]
+ use std::os::windows::fs::symlink_dir;
+
+ // Create symlink directory "foo" to point outside the root
+ let (dir, filename) = ("foo", "bar");
+ symlink_dir(tmpdir.path(), server.path().join(dir)).unwrap();
+
+ let full_path = server.path().join(dir).join(filename);
+ assert!(!full_path.exists());
+
+ // Try to upload
+ let part = multipart::Part::text("this should be uploaded")
+ .file_name(filename)
+ .mime_str("text/plain")?;
+ let form = multipart::Form::new().part("file_to_upload", part);
+
+ let status = Client::new()
+ .post(server.url().join(&format!("/upload?path={}", dir))?)
+ .multipart(form)
+ .send()?
+ .error_for_status();
+
+ // Make sure upload behave as expected
+ assert_eq!(status.is_ok(), ok);
+ assert_eq!(full_path.exists(), ok);
+
+ Ok(())
+}