From bc2d10333b54ab71b7163538bb1bcc69df034053 Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Sun, 24 Aug 2025 23:14:02 +0800 Subject: [PATCH] dufs: backport upstream fixes Including one security fix. Signed-off-by: Tianling Shen --- net/dufs/Makefile | 2 +- ...ir-urls-inherit-noscript-params-614-.patch | 37 ++++++ .../002-fix-perms-on-dufs-A-a-ro-619-.patch | 110 ++++++++++++++++++ ...not-work-for-readonly-annoymous-620-.patch | 96 +++++++++++++++ 4 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 net/dufs/patches/001-feat-make-dir-urls-inherit-noscript-params-614-.patch create mode 100644 net/dufs/patches/002-fix-perms-on-dufs-A-a-ro-619-.patch create mode 100644 net/dufs/patches/003-fix-login-btn-does-not-work-for-readonly-annoymous-620-.patch diff --git a/net/dufs/Makefile b/net/dufs/Makefile index 1d3066de95..2abf392b55 100644 --- a/net/dufs/Makefile +++ b/net/dufs/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dufs PKG_VERSION:=0.44.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/sigoden/dufs/tar.gz/v$(PKG_VERSION)? diff --git a/net/dufs/patches/001-feat-make-dir-urls-inherit-noscript-params-614-.patch b/net/dufs/patches/001-feat-make-dir-urls-inherit-noscript-params-614-.patch new file mode 100644 index 0000000000..acbf91d01c --- /dev/null +++ b/net/dufs/patches/001-feat-make-dir-urls-inherit-noscript-params-614-.patch @@ -0,0 +1,37 @@ +From b2f244a4cfeb492b38ad9b92692e230e04540ea0 Mon Sep 17 00:00:00 2001 +From: sigoden +Date: Sat, 16 Aug 2025 07:36:19 +0800 +Subject: [PATCH] feat: make dir urls inherit `?noscript` params (#614) + +--- + src/noscript.rs | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/src/noscript.rs ++++ b/src/noscript.rs +@@ -55,17 +55,20 @@ pub fn generate_noscript_html(data: &Ind + + fn render_parent() -> String { + let value = "../"; +- format!("{value}") ++ format!("{value}") + } + + fn render_path_item(path: &PathItem) -> String { +- let href = encode_uri(&path.name); +- let suffix = if path.path_type.is_dir() { "/" } else { "" }; +- let name = escape_str_pcdata(&path.name); ++ let mut href = encode_uri(&path.name); ++ let mut name = escape_str_pcdata(&path.name).to_string(); ++ if path.path_type.is_dir() { ++ href.push_str("/?noscript"); ++ name.push('/'); ++ }; + let mtime = format_mtime(path.mtime).unwrap_or_default(); + let size = format_size(path.size, path.path_type); + +- format!("{name}{suffix}{mtime}{size}") ++ format!("{name}{mtime}{size}") + } + + fn format_mtime(mtime: u64) -> Option { diff --git a/net/dufs/patches/002-fix-perms-on-dufs-A-a-ro-619-.patch b/net/dufs/patches/002-fix-perms-on-dufs-A-a-ro-619-.patch new file mode 100644 index 0000000000..46d6d482c9 --- /dev/null +++ b/net/dufs/patches/002-fix-perms-on-dufs-A-a-ro-619-.patch @@ -0,0 +1,110 @@ +From f8a7873582567a85095ca9d2124b185cd3eb2ffd Mon Sep 17 00:00:00 2001 +From: sigoden +Date: Tue, 19 Aug 2025 07:51:52 +0800 +Subject: [PATCH] fix: perms on `dufs -A -a @/:ro` (#619) + +--- + src/auth.rs | 9 ++++++--- + src/server.rs | 4 ++-- + tests/auth.rs | 18 ++++++++++++++++++ + 3 files changed, 26 insertions(+), 5 deletions(-) + +--- a/src/auth.rs ++++ b/src/auth.rs +@@ -30,6 +30,7 @@ lazy_static! { + + #[derive(Debug, Clone, PartialEq)] + pub struct AccessControl { ++ empty: bool, + use_hashed_password: bool, + users: IndexMap, + anonymous: Option, +@@ -38,6 +39,7 @@ pub struct AccessControl { + impl Default for AccessControl { + fn default() -> Self { + AccessControl { ++ empty: true, + use_hashed_password: false, + users: IndexMap::new(), + anonymous: Some(AccessPaths::new(AccessPerm::ReadWrite)), +@@ -48,7 +50,7 @@ impl Default for AccessControl { + impl AccessControl { + pub fn new(raw_rules: &[&str]) -> Result { + if raw_rules.is_empty() { +- return Ok(Default::default()); ++ return Ok(Self::default()); + } + let new_raw_rules = split_rules(raw_rules); + let mut use_hashed_password = false; +@@ -93,13 +95,14 @@ impl AccessControl { + } + + Ok(Self { ++ empty: false, + use_hashed_password, + users, + anonymous, + }) + } + +- pub fn exist(&self) -> bool { ++ pub fn has_users(&self) -> bool { + !self.users.is_empty() + } + +@@ -111,7 +114,7 @@ impl AccessControl { + token: Option<&String>, + guard_options: bool, + ) -> (Option, Option) { +- if self.users.is_empty() { ++ if self.empty { + return (None, Some(AccessPaths::new(AccessPerm::ReadWrite))); + } + +--- a/src/server.rs ++++ b/src/server.rs +@@ -962,7 +962,7 @@ impl Server { + uri_prefix: self.args.uri_prefix.clone(), + allow_upload: self.args.allow_upload, + allow_delete: self.args.allow_delete, +- auth: self.args.auth.exist(), ++ auth: self.args.auth.has_users(), + user, + editable, + }; +@@ -1226,7 +1226,7 @@ impl Server { + allow_search: self.args.allow_search, + allow_archive: self.args.allow_archive, + dir_exists: exist, +- auth: self.args.auth.exist(), ++ auth: self.args.auth.has_users(), + user, + paths, + }; +--- a/tests/auth.rs ++++ b/tests/auth.rs +@@ -126,6 +126,24 @@ fn auth_skip_if_no_auth_user(server: Tes + } + + #[rstest] ++fn auth_no_skip_if_anonymous( ++ #[with(&["--auth", "@/:ro"])] server: TestServer, ++) -> Result<(), Error> { ++ let url = format!("{}index.html", server.url()); ++ let resp = fetch!(b"GET", &url) ++ .basic_auth("user", Some("pass")) ++ .send()?; ++ assert_eq!(resp.status(), 401); ++ let resp = fetch!(b"GET", &url).send()?; ++ assert_eq!(resp.status(), 200); ++ let resp = fetch!(b"DELETE", &url) ++ .basic_auth("user", Some("pass")) ++ .send()?; ++ assert_eq!(resp.status(), 401); ++ Ok(()) ++} ++ ++#[rstest] + fn auth_check( + #[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "-A"])] server: TestServer, + ) -> Result<(), Error> { diff --git a/net/dufs/patches/003-fix-login-btn-does-not-work-for-readonly-annoymous-620-.patch b/net/dufs/patches/003-fix-login-btn-does-not-work-for-readonly-annoymous-620-.patch new file mode 100644 index 0000000000..02d4b9ae21 --- /dev/null +++ b/net/dufs/patches/003-fix-login-btn-does-not-work-for-readonly-annoymous-620-.patch @@ -0,0 +1,96 @@ +From 4016715187db5bd84c7d15ea6abcd99fd4a0a667 Mon Sep 17 00:00:00 2001 +From: sigoden +Date: Tue, 19 Aug 2025 08:58:59 +0800 +Subject: [PATCH] fix: login btn does not work for readonly annoymous (#620) + +--- + assets/index.js | 7 ++++--- + src/server.rs | 13 ++++++++++++- + tests/auth.rs | 16 ++++++++++++++-- + 3 files changed, 30 insertions(+), 6 deletions(-) + +--- a/assets/index.js ++++ b/assets/index.js +@@ -534,7 +534,7 @@ async function setupAuth() { + $loginBtn.classList.remove("hidden"); + $loginBtn.addEventListener("click", async () => { + try { +- await checkAuth(); ++ await checkAuth("login"); + } catch { } + location.reload(); + }); +@@ -782,9 +782,10 @@ async function saveChange() { + } + } + +-async function checkAuth() { ++async function checkAuth(variant) { + if (!DATA.auth) return; +- const res = await fetch(baseUrl(), { ++ const qs = variant ? `?${variant}` : ""; ++ const res = await fetch(baseUrl() + qs, { + method: "CHECKAUTH", + }); + await assertResOK(res); +--- a/src/server.rs ++++ b/src/server.rs +@@ -211,7 +211,18 @@ impl Server { + } + + if method.as_str() == "CHECKAUTH" { +- *res.body_mut() = body_full(user.clone().unwrap_or_default()); ++ match user.clone() { ++ Some(user) => { ++ *res.body_mut() = body_full(user); ++ } ++ None => { ++ if has_query_flag(&query_params, "login") || !access_paths.perm().readwrite() { ++ self.auth_reject(&mut res)? ++ } else { ++ *res.body_mut() = body_full(""); ++ } ++ } ++ } + return Ok(res); + } else if method.as_str() == "LOGOUT" { + self.auth_reject(&mut res)?; +--- a/tests/auth.rs ++++ b/tests/auth.rs +@@ -147,7 +147,7 @@ fn auth_no_skip_if_anonymous( + fn auth_check( + #[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "-A"])] server: TestServer, + ) -> Result<(), Error> { +- let url = format!("{}index.html", server.url()); ++ let url = format!("{}", server.url()); + let resp = fetch!(b"CHECKAUTH", &url).send()?; + assert_eq!(resp.status(), 401); + let resp = send_with_digest_auth(fetch!(b"CHECKAUTH", &url), "user", "pass")?; +@@ -161,7 +161,7 @@ fn auth_check( + fn auth_check2( + #[with(&["--auth", "user:pass@/:rw|user2:pass2@/", "-A"])] server: TestServer, + ) -> Result<(), Error> { +- let url = format!("{}index.html", server.url()); ++ let url = format!("{}", server.url()); + let resp = fetch!(b"CHECKAUTH", &url).send()?; + assert_eq!(resp.status(), 401); + let resp = send_with_digest_auth(fetch!(b"CHECKAUTH", &url), "user", "pass")?; +@@ -171,6 +171,18 @@ fn auth_check2( + Ok(()) + } + ++#[rstest] ++fn auth_check3( ++ #[with(&["--auth", "user:pass@/:rw", "--auth", "@/dir1:rw", "-A"])] server: TestServer, ++) -> Result<(), Error> { ++ let url = format!("{}dir1/", server.url()); ++ let resp = fetch!(b"CHECKAUTH", &url).send()?; ++ assert_eq!(resp.status(), 200); ++ let resp = fetch!(b"CHECKAUTH", format!("{url}?login")).send()?; ++ assert_eq!(resp.status(), 401); ++ Ok(()) ++} ++ + #[rstest] + fn auth_logout( + #[with(&["--auth", "user:pass@/:rw", "-A"])] server: TestServer, -- 2.30.2