aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorcyqsimon <28627918+cyqsimon@users.noreply.github.com>2023-03-22 23:35:31 +0000
committercyqsimon <28627918+cyqsimon@users.noreply.github.com>2023-07-10 05:51:28 +0000
commit489c7d04c824339faf085418c48bd44c75a6da80 (patch)
treeccb04c59208375ac6d7721a55b0bdbcdfde51b6c /src
parentchore: Release miniserve version 0.24.0 (diff)
downloadminiserve-489c7d04c824339faf085418c48bd44c75a6da80.tar.gz
miniserve-489c7d04c824339faf085418c48bd44c75a6da80.zip
Create shared file utiity module
Diffstat (limited to '')
-rw-r--r--src/config.rs2
-rw-r--r--src/file_upload.rs87
-rw-r--r--src/file_utils.rs84
-rw-r--r--src/main.rs1
4 files changed, 88 insertions, 86 deletions
diff --git a/src/config.rs b/src/config.rs
index 8976d35..d52b231 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,7 +16,7 @@ use rustls_pemfile as pemfile;
use crate::{
args::{CliArgs, MediaType},
auth::RequiredAuth,
- file_upload::sanitize_path,
+ file_utils::sanitize_path,
renderer::ThemeSlug,
};
diff --git a/src/file_upload.rs b/src/file_upload.rs
index 2275c73..b9974aa 100644
--- a/src/file_upload.rs
+++ b/src/file_upload.rs
@@ -6,8 +6,8 @@ use std::{
use actix_web::{http::header, HttpRequest, HttpResponse};
use futures::TryStreamExt;
-use crate::errors::ContextualError;
-use crate::listing;
+use crate::{errors::ContextualError, file_utils::sanitize_path};
+use crate::{file_utils::contains_symlink, listing};
/// Saves file data from a multipart form field (`field`) to `file_path`, optionally overwriting
/// existing file.
@@ -214,86 +214,3 @@ pub async fn upload_file(
.append_header((header::LOCATION, return_path))
.finish())
}
-
-/// Guarantee that the path is relative and cannot traverse back to parent directories
-/// and optionally prevent traversing hidden directories.
-///
-/// See the unit tests tests::test_sanitize_path* for examples
-pub fn sanitize_path(path: &Path, traverse_hidden: bool) -> Option<PathBuf> {
- let mut buf = PathBuf::new();
-
- for comp in path.components() {
- match comp {
- Component::Normal(name) => buf.push(name),
- Component::ParentDir => {
- buf.pop();
- }
- _ => (),
- }
- }
-
- // Double-check that all components are Normal and check for hidden dirs
- for comp in buf.components() {
- match comp {
- Component::Normal(_) if traverse_hidden => (),
- Component::Normal(name) if !name.to_str()?.starts_with('.') => (),
- _ => return None,
- }
- }
-
- Some(buf)
-}
-
-/// Returns if a path goes through a symolic link
-fn contains_symlink(path: &PathBuf) -> bool {
- let mut joined_path = PathBuf::new();
- for path_slice in path {
- joined_path = joined_path.join(path_slice);
- if !joined_path.exists() {
- // On Windows, `\\?\` won't exist even though it's the root
- // So, we can't just return here
- // But we don't need to check if it's a symlink since it won't be
- continue;
- }
- if joined_path
- .symlink_metadata()
- .map(|m| m.file_type().is_symlink())
- .unwrap_or(false)
- {
- return true;
- }
- }
- false
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use pretty_assertions::assert_eq;
- use rstest::rstest;
-
- #[rstest]
- #[case("/foo", "foo")]
- #[case("////foo", "foo")]
- #[case("C:/foo", if cfg!(windows) { "foo" } else { "C:/foo" })]
- #[case("../foo", "foo")]
- #[case("../foo/../bar/abc", "bar/abc")]
- fn test_sanitize_path(#[case] input: &str, #[case] output: &str) {
- assert_eq!(
- sanitize_path(Path::new(input), true).unwrap(),
- Path::new(output)
- );
- assert_eq!(
- sanitize_path(Path::new(input), false).unwrap(),
- Path::new(output)
- );
- }
-
- #[rstest]
- #[case(".foo")]
- #[case("/.foo")]
- #[case("foo/.bar/foo")]
- fn test_sanitize_path_no_hidden_files(#[case] input: &str) {
- assert_eq!(sanitize_path(Path::new(input), false), None);
- }
-}
diff --git a/src/file_utils.rs b/src/file_utils.rs
new file mode 100644
index 0000000..fdd68ba
--- /dev/null
+++ b/src/file_utils.rs
@@ -0,0 +1,84 @@
+use std::path::{Component, Path, PathBuf};
+
+/// Guarantee that the path is relative and cannot traverse back to parent directories
+/// and optionally prevent traversing hidden directories.
+///
+/// See the unit tests tests::test_sanitize_path* for examples
+pub fn sanitize_path(path: &Path, traverse_hidden: bool) -> Option<PathBuf> {
+ let mut buf = PathBuf::new();
+
+ for comp in path.components() {
+ match comp {
+ Component::Normal(name) => buf.push(name),
+ Component::ParentDir => {
+ buf.pop();
+ }
+ _ => (),
+ }
+ }
+
+ // Double-check that all components are Normal and check for hidden dirs
+ for comp in buf.components() {
+ match comp {
+ Component::Normal(_) if traverse_hidden => (),
+ Component::Normal(name) if !name.to_str()?.starts_with('.') => (),
+ _ => return None,
+ }
+ }
+
+ Some(buf)
+}
+
+/// Returns if a path goes through a symbolic link
+pub fn contains_symlink(path: &PathBuf) -> bool {
+ let mut joined_path = PathBuf::new();
+ for path_slice in path {
+ joined_path = joined_path.join(path_slice);
+ if !joined_path.exists() {
+ // On Windows, `\\?\` won't exist even though it's the root
+ // So, we can't just return here
+ // But we don't need to check if it's a symlink since it won't be
+ continue;
+ }
+ if joined_path
+ .symlink_metadata()
+ .map(|m| m.file_type().is_symlink())
+ .unwrap_or(false)
+ {
+ return true;
+ }
+ }
+ false
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use pretty_assertions::assert_eq;
+ use rstest::rstest;
+
+ #[rstest]
+ #[case("/foo", "foo")]
+ #[case("////foo", "foo")]
+ #[case("C:/foo", if cfg!(windows) { "foo" } else { "C:/foo" })]
+ #[case("../foo", "foo")]
+ #[case("../foo/../bar/abc", "bar/abc")]
+ fn test_sanitize_path(#[case] input: &str, #[case] output: &str) {
+ assert_eq!(
+ sanitize_path(Path::new(input), true).unwrap(),
+ Path::new(output)
+ );
+ assert_eq!(
+ sanitize_path(Path::new(input), false).unwrap(),
+ Path::new(output)
+ );
+ }
+
+ #[rstest]
+ #[case(".foo")]
+ #[case("/.foo")]
+ #[case("foo/.bar/foo")]
+ fn test_sanitize_path_no_hidden_files(#[case] input: &str) {
+ assert_eq!(sanitize_path(Path::new(input), false), None);
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 2f81baa..a492f4d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,6 +21,7 @@ mod config;
mod consts;
mod errors;
mod file_upload;
+mod file_utils;
mod listing;
mod pipe;
mod renderer;