]> OzVa Git service - ozva-cloud/commitdiff
feat: add option --allow-archive (#152)
authorsigoden <sigoden@gmail.com>
Sat, 10 Dec 2022 03:09:42 +0000 (11:09 +0800)
committerGitHub <noreply@github.com>
Sat, 10 Dec 2022 03:09:42 +0000 (11:09 +0800)
BREAKING CHANGE: explicitly allow download folder as zip file

README.md
assets/index.html
assets/index.js
src/args.rs
src/server.rs
tests/allow.rs
tests/http.rs
tests/render.rs

index 3cbed41086056fad2cf0770a00bee9253bde0542..f3292f123b56ff42a8e10005f8e6ffc93242fb3a 100644 (file)
--- 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
index 7432da21378501670c100608fee7d0d41f45fd8d..b3d7a33c92e8cb9cc9ec47d3fb9143118bc5833f 100644 (file)
@@ -16,7 +16,7 @@
     <div class="breadcrumb"></div>
     <div class="toolbox">
       <div>
-        <a href="?zip" title="Download folder as a .zip file">
+        <a href="?zip" class="zip-root hidden" title="Download folder as a .zip file">
           <svg width="16" height="16" viewBox="0 0 16 16"><path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/><path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/></svg>
         </a>
       </div>
index aef3018644620a3b5fd5b4e1829d4755e3244258..f9e6b83f36acf4a1f38942df28ac738c62a21541 100644 (file)
@@ -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 = `
-    <div class="action-btn">
-      <a href="${url}?zip" title="Download folder as a .zip file">
-        <svg width="16" height="16" viewBox="0 0 16 16"><path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/><path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/></svg>
-      </a>
-    </div>`;
+    if (DATA.allow_archive) {
+      actionDownload = `
+      <div class="action-btn">
+        <a href="${url}?zip" title="Download folder as a .zip file">
+          <svg width="16" height="16" viewBox="0 0 16 16"><path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/><path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/></svg>
+        </a>
+      </div>`;
+    }
   } else {
     actionDownload = `
     <div class="action-btn" >
@@ -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();
index d855e5b27d41609553c748e69c6845a9aabaa4ae..8e6699cbfe6afb40ca28e70b42ed84df55fe1cce 100644 (file)
@@ -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,
index 291ec0ae5874372ce618d99e2853d56995125417..eea71a8656ed2a80cfad1543e28f78a123f9618d 100644 (file)
@@ -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,
 }
 
index 10631b947fcfbb7e569e567a4a87abfd5aef2f93..d5efc0ca67c37a77f08a7aecbd6733f4b9f21978 100644 (file)
@@ -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(())
+}
index 7cb3b77431b43a2d8c7f690a79a58b9ca7fdfdf5..8c223567c4060a424a7f29c759a8d0d5e831d1c9 100644 (file)
@@ -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!(
index 6f0b60bac81b29051274dc6e41d6fa1e72169023..3a8e9f2df1a960751603567e8837204e7b1752e1 100644 (file)
@@ -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!(