From 8d9705caa40b6ed54e8a3350694e67a50c359009 Mon Sep 17 00:00:00 2001 From: sigoden Date: Sat, 10 Dec 2022 11:09:42 +0800 Subject: [PATCH] feat: add option --allow-archive (#152) BREAKING CHANGE: explicitly allow download folder as zip file --- README.md | 1 + assets/index.html | 2 +- assets/index.js | 19 +++++++++++++------ src/args.rs | 9 +++++++++ src/server.rs | 13 ++++++++++++- tests/allow.rs | 19 +++++++++++++++++++ tests/http.rs | 4 ++-- tests/render.rs | 4 +++- 8 files changed, 60 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3cbed41..f3292f1 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Options: --allow-delete Allow delete files/folders --allow-search Allow search files/folders --allow-symlink Allow symlink to files/folders outside root directory + --allow-archive Allow zip archive generation --enable-cors Enable CORS, sets `Access-Control-Allow-Origin: *` --render-index Serve index.html when requesting a directory, returns 404 if not found index.html --render-try-index Serve index.html when requesting a directory, returns directory listing if not found index.html diff --git a/assets/index.html b/assets/index.html index 7432da2..b3d7a33 100644 --- a/assets/index.html +++ b/assets/index.html @@ -16,7 +16,7 @@
- +
diff --git a/assets/index.js b/assets/index.js index aef3018..f9e6b83 100644 --- a/assets/index.js +++ b/assets/index.js @@ -14,6 +14,7 @@ * @property {boolean} allow_upload * @property {boolean} allow_delete * @property {boolean} allow_search + * @property {boolean} allow_archive * @property {boolean} dir_exists */ @@ -273,12 +274,14 @@ function addPath(file, index) { let actionMove = ""; if (file.path_type.endsWith("Dir")) { url += "/"; - actionDownload = ` -
- - - -
`; + if (DATA.allow_archive) { + actionDownload = ` +
+ + + +
`; + } } else { actionDownload = `
@@ -528,6 +531,10 @@ function ready() { } } + if (DATA.allow_archive) { + document.querySelector(".zip-root").classList.remove("hidden"); + } + addBreadcrumb(DATA.href, DATA.uri_prefix); renderPathsTableHead(); renderPathsTableBody(); diff --git a/src/args.rs b/src/args.rs index d855e5b..8e6699c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -108,6 +108,12 @@ pub fn build_cli() -> Command { .action(ArgAction::SetTrue) .help("Allow symlink to files/folders outside root directory"), ) + .arg( + Arg::new("allow-archive") + .long("allow-archive") + .action(ArgAction::SetTrue) + .help("Allow zip archive generation"), + ) .arg( Arg::new("enable-cors") .long("enable-cors") @@ -191,6 +197,7 @@ pub struct Args { pub allow_delete: bool, pub allow_search: bool, pub allow_symlink: bool, + pub allow_archive: bool, pub render_index: bool, pub render_spa: bool, pub render_try_index: bool, @@ -244,6 +251,7 @@ impl Args { let allow_delete = matches.get_flag("allow-all") || matches.get_flag("allow-delete"); let allow_search = matches.get_flag("allow-all") || matches.get_flag("allow-search"); let allow_symlink = matches.get_flag("allow-all") || matches.get_flag("allow-symlink"); + let allow_archive = matches.get_flag("allow-all") || matches.get_flag("allow-archive"); let render_index = matches.get_flag("render-index"); let render_try_index = matches.get_flag("render-try-index"); let render_spa = matches.get_flag("render-spa"); @@ -286,6 +294,7 @@ impl Args { allow_upload, allow_search, allow_symlink, + allow_archive, render_index, render_try_index, render_spa, diff --git a/src/server.rs b/src/server.rs index 291ec0a..eea71a8 100644 --- a/src/server.rs +++ b/src/server.rs @@ -182,6 +182,7 @@ impl Server { let allow_upload = self.args.allow_upload; let allow_delete = self.args.allow_delete; let allow_search = self.args.allow_search; + let allow_archive = self.args.allow_archive; let render_index = self.args.render_index; let render_spa = self.args.render_spa; let render_try_index = self.args.render_try_index; @@ -195,7 +196,11 @@ impl Server { Method::GET | Method::HEAD => { if is_dir { if render_try_index { - if query_params.contains_key("zip") { + if allow_archive && query_params.contains_key("zip") { + if !allow_archive { + status_not_found(&mut res); + return Ok(res); + } self.handle_zip_dir(path, head_only, &mut res).await?; } else if allow_search && query_params.contains_key("q") { self.handle_search_dir(path, &query_params, head_only, &mut res) @@ -214,6 +219,10 @@ impl Server { self.handle_render_index(path, &query_params, headers, head_only, &mut res) .await?; } else if query_params.contains_key("zip") { + if !allow_archive { + status_not_found(&mut res); + return Ok(res); + } self.handle_zip_dir(path, head_only, &mut res).await?; } else if allow_search && query_params.contains_key("q") { self.handle_search_dir(path, &query_params, head_only, &mut res) @@ -824,6 +833,7 @@ impl Server { allow_upload: self.args.allow_upload, allow_delete: self.args.allow_delete, allow_search: self.args.allow_search, + allow_archive: self.args.allow_archive, dir_exists: exist, }; let data = serde_json::to_string(&data).unwrap(); @@ -984,6 +994,7 @@ struct IndexData { allow_upload: bool, allow_delete: bool, allow_search: bool, + allow_archive: bool, dir_exists: bool, } diff --git a/tests/allow.rs b/tests/allow.rs index 10631b9..d5efc0c 100644 --- a/tests/allow.rs +++ b/tests/allow.rs @@ -20,6 +20,13 @@ fn default_not_allow_delete(server: TestServer) -> Result<(), Error> { Ok(()) } +#[rstest] +fn default_not_allow_archive(server: TestServer) -> Result<(), Error> { + let resp = reqwest::blocking::get(format!("{}?zip", server.url()))?; + assert_eq!(resp.status(), 404); + Ok(()) +} + #[rstest] fn default_not_exist_dir(server: TestServer) -> Result<(), Error> { let resp = reqwest::blocking::get(format!("{}404/", server.url()))?; @@ -71,3 +78,15 @@ fn allow_search(#[with(&["--allow-search"])] server: TestServer) -> Result<(), E } Ok(()) } + +#[rstest] +fn allow_archive(#[with(&["--allow-archive"])] server: TestServer) -> Result<(), Error> { + let resp = reqwest::blocking::get(format!("{}?zip", server.url()))?; + assert_eq!(resp.status(), 200); + assert_eq!( + resp.headers().get("content-type").unwrap(), + "application/zip" + ); + assert!(resp.headers().contains_key("content-disposition")); + Ok(()) +} diff --git a/tests/http.rs b/tests/http.rs index 7cb3b77..8c22356 100644 --- a/tests/http.rs +++ b/tests/http.rs @@ -38,7 +38,7 @@ fn head_dir_404(server: TestServer) -> Result<(), Error> { } #[rstest] -fn get_dir_zip(server: TestServer) -> Result<(), Error> { +fn get_dir_zip(#[with(&["-A"])] server: TestServer) -> Result<(), Error> { let resp = reqwest::blocking::get(format!("{}?zip", server.url()))?; assert_eq!(resp.status(), 200); assert_eq!( @@ -50,7 +50,7 @@ fn get_dir_zip(server: TestServer) -> Result<(), Error> { } #[rstest] -fn head_dir_zip(server: TestServer) -> Result<(), Error> { +fn head_dir_zip(#[with(&["-A"])] server: TestServer) -> Result<(), Error> { let resp = fetch!(b"HEAD", format!("{}?zip", server.url())).send()?; assert_eq!(resp.status(), 200); assert_eq!( diff --git a/tests/render.rs b/tests/render.rs index 6f0b60b..3a8e9f2 100644 --- a/tests/render.rs +++ b/tests/render.rs @@ -40,7 +40,9 @@ fn render_try_index2(#[with(&["--render-try-index"])] server: TestServer) -> Res } #[rstest] -fn render_try_index3(#[with(&["--render-try-index"])] server: TestServer) -> Result<(), Error> { +fn render_try_index3( + #[with(&["--render-try-index", "--allow-archive"])] server: TestServer, +) -> Result<(), Error> { let resp = reqwest::blocking::get(format!("{}{}?zip", server.url(), DIR_NO_INDEX))?; assert_eq!(resp.status(), 200); assert_eq!(