Compare commits

..

11 Commits

Author SHA1 Message Date
sigoden
22cf74e3c0 update deps 2024-02-13 03:16:57 +00:00
sigoden
6a6ac37be4 chore: release v0.40.0 2024-02-13 01:19:40 +00:00
sigoden
920b70abc4 refactor: improve resolve_path and handle_assets, abandon guard_path (#360) 2024-02-07 16:27:22 +08:00
sigoden
015713bc6d chore: update deps 2024-02-06 09:32:31 +00:00
sigoden
3c75a9c4cc fix: guard req and destination path (#359) 2024-02-06 17:23:18 +08:00
sigoden
871e8276ff chore: add SECURITY.md 2024-02-05 00:09:25 +00:00
sigoden
f92c8ee91d refactor: improve invalid auth (#356) 2024-01-19 10:25:11 +08:00
sigoden
95eb648411 feat: revert supporting for forbidden permission (#352) 2024-01-17 11:31:26 +08:00
sigoden
3354b1face refactor: do not try to bind ipv6 if no ipv6 (#348) 2024-01-16 09:03:27 +08:00
sigoden
9b348fc945 chore: fix typos 2024-01-15 12:53:59 +00:00
sigoden
e1fabc7349 chore: update readme 2024-01-11 09:07:40 +00:00
13 changed files with 352 additions and 296 deletions

View File

@@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [0.40.0] - 2024-02-13
### Bug Fixes
- Guard req and destination path ([#359](https://github.com/sigoden/dufs/issues/359))
### Features
- Revert supporting for forbidden permission ([#352](https://github.com/sigoden/dufs/issues/352))
### Refactor
- Do not try to bind ipv6 if no ipv6 ([#348](https://github.com/sigoden/dufs/issues/348))
- Improve invalid auth ([#356](https://github.com/sigoden/dufs/issues/356))
- Improve resolve_path and handle_assets, abandon guard_path ([#360](https://github.com/sigoden/dufs/issues/360))
## [0.39.0] - 2024-01-11 ## [0.39.0] - 2024-01-11
### Bug Fixes ### Bug Fixes

270
Cargo.lock generated
View File

@@ -49,9 +49,9 @@ dependencies = [
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.5" version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@@ -63,9 +63,9 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.4" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
@@ -103,9 +103,9 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "2.0.12" version = "2.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"bstr", "bstr",
@@ -118,9 +118,9 @@ dependencies = [
[[package]] [[package]]
name = "assert_fs" name = "assert_fs"
version = "1.1.0" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc5d78e9048d836d12a0c0040ca5f45b18a94d204b4ba4f677a8a7de162426b" checksum = "2cd762e110c8ed629b11b6cde59458cc1c71de78ebbcc30099fc8e0403a2a2ec"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"doc-comment", "doc-comment",
@@ -133,9 +133,9 @@ dependencies = [
[[package]] [[package]]
name = "async-compression" name = "async-compression"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c"
dependencies = [ dependencies = [
"bzip2", "bzip2",
"flate2", "flate2",
@@ -218,9 +218,9 @@ dependencies = [
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.6" version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
@@ -236,9 +236,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.1" version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@@ -295,12 +295,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" checksum = "9b918671670962b48bc23753aef0c51d072dca6f52f01f800854ada6ddb7f7d3"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -321,30 +318,30 @@ dependencies = [
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.31" version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
"num-traits", "num-traits",
"windows-targets 0.48.5", "windows-targets 0.52.0",
] ]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.14" version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2" checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
] ]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.14" version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370" checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -355,9 +352,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "4.4.6" version = "4.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97aeaa95557bd02f23fbb662f981670c3d20c5a26e69f7354b28f57092437fcd" checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3"
dependencies = [ dependencies = [
"clap", "clap",
] ]
@@ -410,9 +407,9 @@ dependencies = [
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@@ -501,7 +498,7 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "dufs" name = "dufs"
version = "0.39.0" version = "0.40.0"
dependencies = [ dependencies = [
"alphanumeric-sort", "alphanumeric-sort",
"anyhow", "anyhow",
@@ -555,12 +552,6 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.33" version = "0.8.33"
@@ -782,20 +773,20 @@ dependencies = [
[[package]] [[package]]
name = "globwalk" name = "globwalk"
version = "0.8.1" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.2",
"ignore", "ignore",
"walkdir", "walkdir",
] ]
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.23" version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@@ -812,9 +803,9 @@ dependencies = [
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991910e35c615d8cab86b5ab04be67e6ad24d2bf5f4f11fdbbed26da999bbeab" checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@@ -861,9 +852,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.3" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
[[package]] [[package]]
name = "hex" name = "hex"
@@ -949,7 +940,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2 0.3.23", "h2 0.3.24",
"http 0.2.11", "http 0.2.11",
"http-body 0.4.6", "http-body 0.4.6",
"httparse", "httparse",
@@ -972,7 +963,7 @@ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"h2 0.4.1", "h2 0.4.2",
"http 1.0.0", "http 1.0.0",
"http-body 1.0.0", "http-body 1.0.0",
"httparse", "httparse",
@@ -998,12 +989,11 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel",
"futures-util", "futures-util",
"http 1.0.0", "http 1.0.0",
"http-body 1.0.0", "http-body 1.0.0",
@@ -1011,14 +1001,13 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.59" version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
@@ -1075,9 +1064,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.1.0" version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@@ -1089,15 +1078,6 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.10"
@@ -1106,9 +1086,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.66" version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@@ -1121,15 +1101,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.152" version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.12" version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]] [[package]]
name = "log" name = "log"
@@ -1188,9 +1168,9 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.1" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [ dependencies = [
"adler", "adler",
] ]
@@ -1214,9 +1194,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.17" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@@ -1260,18 +1240,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.3" version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "1.1.3" version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1292,9 +1272,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.28" version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
[[package]] [[package]]
name = "port_check" name = "port_check"
@@ -1310,14 +1290,13 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "3.0.4" version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"difflib", "difflib",
"float-cmp", "float-cmp",
"itertools",
"normalize-line-endings", "normalize-line-endings",
"predicates-core", "predicates-core",
"regex", "regex",
@@ -1341,9 +1320,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.76" version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -1387,20 +1366,11 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.2" version = "1.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1410,9 +1380,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.3" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1433,16 +1403,16 @@ checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.23" version = "0.11.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2 0.3.23", "h2 0.3.24",
"http 0.2.11", "http 0.2.11",
"http-body 0.4.6", "http-body 0.4.6",
"hyper 0.14.28", "hyper 0.14.28",
@@ -1460,6 +1430,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper",
"system-configuration", "system-configuration",
"tokio", "tokio",
"tokio-rustls 0.24.1", "tokio-rustls 0.24.1",
@@ -1532,11 +1503,11 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.28" version = "0.38.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.2",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@@ -1564,7 +1535,7 @@ dependencies = [
"log", "log",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki 0.102.1", "rustls-webpki 0.102.2",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@@ -1590,9 +1561,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
@@ -1606,9 +1577,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.102.1" version = "0.102.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b" checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610"
dependencies = [ dependencies = [
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
@@ -1648,18 +1619,18 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.195" version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.195" version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1668,9 +1639,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.111" version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -1691,9 +1662,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.9.30" version = "0.9.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
@@ -1804,6 +1775,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@@ -1827,13 +1804,12 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.9.0" version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"redox_syscall",
"rustix", "rustix",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@@ -1856,18 +1832,18 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1891,9 +1867,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.35.1" version = "1.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@@ -2002,9 +1978,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
@@ -2058,9 +2034,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.6.1" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"rand", "rand",
@@ -2108,9 +2084,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.89" version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@@ -2118,9 +2094,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.89" version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
@@ -2133,9 +2109,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.39" version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -2145,9 +2121,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.89" version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -2155,9 +2131,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.89" version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2168,15 +2144,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.89" version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.66" version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@@ -2184,9 +2160,9 @@ dependencies = [
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.25.3" version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "dufs" name = "dufs"
version = "0.39.0" version = "0.40.0"
edition = "2021" edition = "2021"
authors = ["sigoden <sigoden@gmail.com>"] authors = ["sigoden <sigoden@gmail.com>"]
description = "Dufs is a distinctive utility file server" description = "Dufs is a distinctive utility file server"
@@ -11,8 +11,8 @@ categories = ["command-line-utilities", "web-programming::http-server"]
keywords = ["static", "file", "server", "webdav", "cli"] keywords = ["static", "file", "server", "webdav", "cli"]
[dependencies] [dependencies]
clap = { version = "4", features = ["wrap_help", "env"] } clap = { version = "~4.4", features = ["wrap_help", "env"] }
clap_complete = "4" clap_complete = "~4.4"
chrono = { version = "0.4", default-features = false, features = ["clock"] } chrono = { version = "0.4", default-features = false, features = ["clock"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"]} tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"]}
tokio-util = { version = "0.7", features = ["io-util", "compat"] } tokio-util = { version = "0.7", features = ["io-util", "compat"] }
@@ -29,7 +29,7 @@ rustls-pemfile = { version = "2.0", optional = true }
tokio-rustls = { version = "0.25", optional = true } tokio-rustls = { version = "0.25", optional = true }
md5 = "0.7" md5 = "0.7"
lazy_static = "1.4" lazy_static = "1.4"
uuid = { version = "1.4", features = ["v4", "fast-rng"] } uuid = { version = "1.7", features = ["v4", "fast-rng"] }
urlencoding = "2.1" urlencoding = "2.1"
xml-rs = "0.8" xml-rs = "0.8"
log = "0.4" log = "0.4"
@@ -42,12 +42,12 @@ content_inspector = "0.2"
anyhow = "1.0" anyhow = "1.0"
chardetng = "0.1" chardetng = "0.1"
glob = "0.3" glob = "0.3"
indexmap = "2.0" indexmap = "2.2"
serde_yaml = "0.9" serde_yaml = "0.9"
sha-crypt = "0.5" sha-crypt = "0.5"
base64 = "0.21" base64 = "0.21"
smart-default = "0.7" smart-default = "0.7"
rustls-pki-types = "1.0" rustls-pki-types = "1.2"
hyper-util = { version = "0.1", features = ["server-auto", "tokio"] } hyper-util = { version = "0.1", features = ["server-auto", "tokio"] }
http-body-util = "0.1" http-body-util = "0.1"
bytes = "1.5" bytes = "1.5"

View File

@@ -151,63 +151,63 @@ dufs --tls-cert my.crt --tls-key my.key
Upload a file Upload a file
``` ```sh
curl -T path-to-file http://127.0.0.1:5000/new-path/path-to-file curl -T path-to-file http://127.0.0.1:5000/new-path/path-to-file
``` ```
Download a file Download a file
``` ```sh
curl http://127.0.0.1:5000/path-to-file curl http://127.0.0.1:5000/path-to-file
``` ```
Download a folder as zip file Download a folder as zip file
``` ```sh
curl -o path-to-folder.zip http://127.0.0.1:5000/path-to-folder?zip curl -o path-to-folder.zip http://127.0.0.1:5000/path-to-folder?zip
``` ```
Delete a file/folder Delete a file/folder
``` ```sh
curl -X DELETE http://127.0.0.1:5000/path-to-file-or-folder curl -X DELETE http://127.0.0.1:5000/path-to-file-or-folder
``` ```
Create a directory Create a directory
``` ```sh
curl -X MKCOL https://127.0.0.1:5000/path-to-folder curl -X MKCOL https://127.0.0.1:5000/path-to-folder
``` ```
Move the file/folder to the new path Move the file/folder to the new path
``` ```sh
curl -X MOVE https://127.0.0.1:5000/path -H "Destination: https://127.0.0.1:5000/new-path" curl -X MOVE https://127.0.0.1:5000/path -H "Destination: https://127.0.0.1:5000/new-path"
``` ```
List/search directory contents List/search directory contents
``` ```sh
curl http://127.0.0.1:5000?q=Dockerfile # search for files, similar to `find -name Dockerfile` curl http://127.0.0.1:5000?q=Dockerfile # search for files, similar to `find -name Dockerfile`
curl http://127.0.0.1:5000?simple # output names only, similar to `ls -1` curl http://127.0.0.1:5000?simple # output names only, similar to `ls -1`
curl http://127.0.0.1:5000?json # output paths in json format curl http://127.0.0.1:5000?json # output paths in json format
``` ```
With authorization With authorization (Both basic or digest auth works)
``` ```sh
curl http://127.0.0.1:5000/file --user user:pass # basic auth curl http://127.0.0.1:5000/file --user user:pass # basic auth
curl http://127.0.0.1:5000/file --user user:pass --digest # digest auth curl http://127.0.0.1:5000/file --user user:pass --digest # digest auth
``` ```
Resumable downloads Resumable downloads
``` ```sh
curl -C- -o file http://127.0.0.1:5000/file curl -C- -o file http://127.0.0.1:5000/file
``` ```
Resumable uploads Resumable uploads
``` ```sh
upload_offset=$(curl -I -s http://127.0.0.1:5000/file | tr -d '\r' | sed -n 's/content-length: //p') upload_offset=$(curl -I -s http://127.0.0.1:5000/file | tr -d '\r' | sed -n 's/content-length: //p')
dd skip=$upload_offset if=file status=none ibs=1 | \ dd skip=$upload_offset if=file status=none ibs=1 | \
curl -X PATCH -H "X-Update-Range: append" --data-binary @- http://127.0.0.1:5000/file curl -X PATCH -H "X-Update-Range: append" --data-binary @- http://127.0.0.1:5000/file
@@ -222,17 +222,17 @@ Dufs supports account based access control. You can control who can do what on w
``` ```
dufs -a admin:admin@/:rw -a guest:guest@/ dufs -a admin:admin@/:rw -a guest:guest@/
dufs -a user:pass@/:rw,/dir1,/dir2:- -a @/ dufs -a user:pass@/:rw,/dir1 -a @/
``` ```
1. Use `@` to separate the account and paths. No account means anonymous user. 1. Use `@` to separate the account and paths. No account means anonymous user.
2. Use `:` to separate the username and password of the account. 2. Use `:` to separate the username and password of the account.
3. Use `,` to separate paths. 3. Use `,` to separate paths.
4. Use path suffix `:rw`, `:ro`, `:-` to set permissions: `read-write`, `read-only`, `forbidden`. `:ro` can be omitted. 4. Use path suffix `:rw`/`:ro` set permissions: `read-write`/`read-only`. `:ro` can be omitted.
- `-a admin:admin@/:rw`: `admin` has complete permissions for all paths. - `-a admin:admin@/:rw`: `admin` has complete permissions for all paths.
- `-a guest:guest@/`: `guest` has read-only permissions for all paths. - `-a guest:guest@/`: `guest` has read-only permissions for all paths.
- `-a user:pass@/:rw,/dir1,/dir2:-`: `user` has read-write permissions for `/*`, has read-only permissions for `/dir1/*`, but is fordden for `/dir2/*`. - `-a user:pass@/:rw,/dir1`: `user` has read-write permissions for `/*`, has read-only permissions for `/dir1/*`.
- `-a @/`: All paths is publicly accessible, everyone can view/download it. - `-a @/`: All paths is publicly accessible, everyone can view/download it.
> There are no restrictions on using ':' and '@' characters in a password. For example, `user:pa:ss@1@/:rw` is valid, the password is `pa:ss@1`. > There are no restrictions on using ':' and '@' characters in a password. For example, `user:pa:ss@1@/:rw` is valid, the password is `pa:ss@1`.
@@ -402,7 +402,7 @@ Your assets folder must contains a `index.html` file.
## License ## License
Copyright (c) 2022 dufs-developers. Copyright (c) 2022-2024 dufs-developers.
dufs is made available under the terms of either the MIT License or the Apache License 2.0, at your option. dufs is made available under the terms of either the MIT License or the Apache License 2.0, at your option.

21
SECURITY.md Normal file
View File

@@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
The latest release of *dufs* is supported. The fixes for any security issues found will be included
in the next release.
## Reporting a Vulnerability
Please [use *dufs*'s security advisory reporting tool provided by
GitHub](https://github.com/sigoden/dufs/security/advisories/new) to report security issues.
We strive to fix security issues as quickly as possible. Across the industry, often the developers'
slowness in developing and releasing a fix is the biggest delay in the process; we take pride in
minimizing this delay as much as we practically can. We encourage you to also minimize the delay
between when you find an issue and when you contact us. You do not need to convince us to take your
report seriously. You don't need to create a PoC or a patch if that would slow down your reporting.
You don't need an elaborate write-up. A short, informal note about the issue is good. We can always
communicate later to fill in any details we need after that first note is shared with us.

View File

@@ -29,15 +29,15 @@ lazy_static! {
pub struct AccessControl { pub struct AccessControl {
use_hashed_password: bool, use_hashed_password: bool,
users: IndexMap<String, (String, AccessPaths)>, users: IndexMap<String, (String, AccessPaths)>,
anony: Option<AccessPaths>, anonymous: Option<AccessPaths>,
} }
impl Default for AccessControl { impl Default for AccessControl {
fn default() -> Self { fn default() -> Self {
AccessControl { AccessControl {
use_hashed_password: false, use_hashed_password: false,
anony: Some(AccessPaths::new(AccessPerm::ReadWrite)),
users: IndexMap::new(), users: IndexMap::new(),
anonymous: Some(AccessPaths::new(AccessPerm::ReadWrite)),
} }
} }
} }
@@ -66,15 +66,15 @@ impl AccessControl {
account_paths_pairs.push((user, pass, paths)); account_paths_pairs.push((user, pass, paths));
} }
} }
let mut anony = None; let mut anonymous = None;
if let Some(paths) = annoy_paths { if let Some(paths) = annoy_paths {
let mut access_paths = AccessPaths::default(); let mut access_paths = AccessPaths::default();
access_paths.merge(paths); access_paths.merge(paths);
anony = Some(access_paths); anonymous = Some(access_paths);
} }
let mut users = IndexMap::new(); let mut users = IndexMap::new();
for (user, pass, paths) in account_paths_pairs.into_iter() { for (user, pass, paths) in account_paths_pairs.into_iter() {
let mut access_paths = anony.clone().unwrap_or_default(); let mut access_paths = anonymous.clone().unwrap_or_default();
access_paths access_paths
.merge(paths) .merge(paths)
.ok_or_else(|| anyhow!("Invalid auth `{user}:{pass}@{paths}"))?; .ok_or_else(|| anyhow!("Invalid auth `{user}:{pass}@{paths}"))?;
@@ -87,7 +87,7 @@ impl AccessControl {
Ok(Self { Ok(Self {
use_hashed_password, use_hashed_password,
users, users,
anony, anonymous,
}) })
} }
@@ -109,18 +109,18 @@ impl AccessControl {
} }
if check_auth(authorization, method.as_str(), &user, pass).is_some() { if check_auth(authorization, method.as_str(), &user, pass).is_some() {
return (Some(user), paths.find(path, !is_readonly_method(method))); return (Some(user), paths.find(path, !is_readonly_method(method)));
} else {
return (None, None);
} }
} }
} }
return (None, None);
} }
if method == Method::OPTIONS { if method == Method::OPTIONS {
return (None, Some(AccessPaths::new(AccessPerm::ReadOnly))); return (None, Some(AccessPaths::new(AccessPerm::ReadOnly)));
} }
if let Some(paths) = self.anony.as_ref() { if let Some(paths) = self.anonymous.as_ref() {
return (None, paths.find(path, !is_readonly_method(method))); return (None, paths.find(path, !is_readonly_method(method)));
} }
@@ -147,7 +147,7 @@ impl AccessPaths {
} }
pub fn set_perm(&mut self, perm: AccessPerm) { pub fn set_perm(&mut self, perm: AccessPerm) {
if !perm.inherit() { if !perm.indexonly() {
self.perm = perm; self.perm = perm;
} }
} }
@@ -158,7 +158,6 @@ impl AccessPaths {
None => (item, AccessPerm::ReadOnly), None => (item, AccessPerm::ReadOnly),
Some((path, "ro")) => (path, AccessPerm::ReadOnly), Some((path, "ro")) => (path, AccessPerm::ReadOnly),
Some((path, "rw")) => (path, AccessPerm::ReadWrite), Some((path, "rw")) => (path, AccessPerm::ReadWrite),
Some((path, "-")) => (path, AccessPerm::Forbidden),
_ => return None, _ => return None,
}; };
self.add(path, perm); self.add(path, perm);
@@ -193,9 +192,6 @@ impl AccessPaths {
.filter(|v| !v.is_empty()) .filter(|v| !v.is_empty())
.collect(); .collect();
let target = self.find_impl(&parts, self.perm)?; let target = self.find_impl(&parts, self.perm)?;
if target.perm().forbidden() {
return None;
}
if writable && !target.perm().readwrite() { if writable && !target.perm().readwrite() {
return None; return None;
} }
@@ -203,13 +199,13 @@ impl AccessPaths {
} }
fn find_impl(&self, parts: &[&str], perm: AccessPerm) -> Option<AccessPaths> { fn find_impl(&self, parts: &[&str], perm: AccessPerm) -> Option<AccessPaths> {
let perm = if !self.perm.inherit() { let perm = if !self.perm.indexonly() {
self.perm self.perm
} else { } else {
perm perm
}; };
if parts.is_empty() { if parts.is_empty() {
if perm.inherit() { if perm.indexonly() {
return Some(self.clone()); return Some(self.clone());
} else { } else {
return Some(AccessPaths::new(perm)); return Some(AccessPaths::new(perm));
@@ -218,7 +214,7 @@ impl AccessPaths {
let child = match self.children.get(parts[0]) { let child = match self.children.get(parts[0]) {
Some(v) => v, Some(v) => v,
None => { None => {
if perm.inherit() { if perm.indexonly() {
return None; return None;
} else { } else {
return Some(AccessPaths::new(perm)); return Some(AccessPaths::new(perm));
@@ -233,7 +229,7 @@ impl AccessPaths {
} }
pub fn child_paths(&self, base: &Path) -> Vec<PathBuf> { pub fn child_paths(&self, base: &Path) -> Vec<PathBuf> {
if !self.perm().inherit() { if !self.perm().indexonly() {
return vec![base.to_path_buf()]; return vec![base.to_path_buf()];
} }
let mut output = vec![]; let mut output = vec![];
@@ -244,7 +240,7 @@ impl AccessPaths {
fn child_paths_impl(&self, output: &mut Vec<PathBuf>, base: &Path) { fn child_paths_impl(&self, output: &mut Vec<PathBuf>, base: &Path) {
for (name, child) in self.children.iter() { for (name, child) in self.children.iter() {
let base = base.join(name); let base = base.join(name);
if child.perm().inherit() { if child.perm().indexonly() {
child.child_paths_impl(output, &base); child.child_paths_impl(output, &base);
} else { } else {
output.push(base) output.push(base)
@@ -256,24 +252,19 @@ impl AccessPaths {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum AccessPerm { pub enum AccessPerm {
#[default] #[default]
Inherit, IndexOnly,
ReadOnly, ReadOnly,
ReadWrite, ReadWrite,
Forbidden,
} }
impl AccessPerm { impl AccessPerm {
pub fn inherit(&self) -> bool { pub fn indexonly(&self) -> bool {
self == &AccessPerm::Inherit self == &AccessPerm::IndexOnly
} }
pub fn readwrite(&self) -> bool { pub fn readwrite(&self) -> bool {
self == &AccessPerm::ReadWrite self == &AccessPerm::ReadWrite
} }
pub fn forbidden(&self) -> bool {
self == &AccessPerm::Forbidden
}
} }
pub fn www_authenticate(res: &mut Response, args: &Args) -> Result<()> { pub fn www_authenticate(res: &mut Response, args: &Args) -> Result<()> {
@@ -576,7 +567,6 @@ mod tests {
paths.add("/dir1", AccessPerm::ReadWrite); paths.add("/dir1", AccessPerm::ReadWrite);
paths.add("/dir2/dir21", AccessPerm::ReadWrite); paths.add("/dir2/dir21", AccessPerm::ReadWrite);
paths.add("/dir2/dir21/dir211", AccessPerm::ReadOnly); paths.add("/dir2/dir21/dir211", AccessPerm::ReadOnly);
paths.add("/dir2/dir21/dir212", AccessPerm::Forbidden);
paths.add("/dir2/dir22", AccessPerm::ReadOnly); paths.add("/dir2/dir22", AccessPerm::ReadOnly);
paths.add("/dir2/dir22/dir221", AccessPerm::ReadWrite); paths.add("/dir2/dir22/dir221", AccessPerm::ReadWrite);
paths.add("/dir2/dir23/dir231", AccessPerm::ReadWrite); paths.add("/dir2/dir23/dir231", AccessPerm::ReadWrite);
@@ -621,6 +611,5 @@ mod tests {
Some(AccessPaths::new(AccessPerm::ReadOnly)) Some(AccessPaths::new(AccessPerm::ReadOnly))
); );
assert_eq!(paths.find("dir2/dir21/dir211/file", true), None); assert_eq!(paths.find("dir2/dir21/dir211/file", true), None);
assert_eq!(paths.find("dir2/dir21/dir212", false), None);
} }
} }

View File

@@ -43,9 +43,11 @@ async fn main() -> Result<()> {
print_completions(*generator, &mut cmd); print_completions(*generator, &mut cmd);
return Ok(()); return Ok(());
} }
let args = Args::parse(matches)?; let mut args = Args::parse(matches)?;
let (new_addrs, print_addrs) = check_addrs(&args)?;
args.addrs = new_addrs;
let running = Arc::new(AtomicBool::new(true)); let running = Arc::new(AtomicBool::new(true));
let listening = print_listening(&args)?; let listening = print_listening(&args, &print_addrs)?;
let handles = serve(args, running.clone())?; let handles = serve(args, running.clone())?;
println!("{listening}"); println!("{listening}");
@@ -189,42 +191,64 @@ fn create_listener(addr: SocketAddr) -> Result<TcpListener> {
Ok(listener) Ok(listener)
} }
fn print_listening(args: &Args) -> Result<String> { fn check_addrs(args: &Args) -> Result<(Vec<BindAddr>, Vec<BindAddr>)> {
let mut output = String::new(); let mut new_addrs = vec![];
let mut bind_addrs = vec![]; let mut print_addrs = vec![];
let (mut ipv4, mut ipv6) = (false, false); let (ipv4_addrs, ipv6_addrs) = interface_addrs()?;
for bind_addr in args.addrs.iter() { for bind_addr in args.addrs.iter() {
match bind_addr { match bind_addr {
BindAddr::Address(ip) => { BindAddr::Address(ip) => match &ip {
if ip.is_unspecified() { IpAddr::V4(_) => {
if ip.is_ipv6() { if !ipv4_addrs.is_empty() {
ipv6 = true; new_addrs.push(bind_addr.clone());
} else { if ip.is_unspecified() {
ipv4 = true; print_addrs.extend(ipv4_addrs.clone());
} else {
print_addrs.push(bind_addr.clone());
}
} }
} else {
bind_addrs.push(bind_addr.clone());
} }
} IpAddr::V6(_) => {
_ => bind_addrs.push(bind_addr.clone()), if !ipv6_addrs.is_empty() {
} new_addrs.push(bind_addr.clone());
} if ip.is_unspecified() {
if ipv4 || ipv6 { print_addrs.extend(ipv6_addrs.clone());
let ifaces = } else {
if_addrs::get_if_addrs().with_context(|| "Failed to get local interface addresses")?; print_addrs.push(bind_addr.clone())
for iface in ifaces.into_iter() { }
let local_ip = iface.ip(); }
if ipv4 && local_ip.is_ipv4() { }
bind_addrs.push(BindAddr::Address(local_ip)) },
} _ => {
if ipv6 && local_ip.is_ipv6() { new_addrs.push(bind_addr.clone());
bind_addrs.push(BindAddr::Address(local_ip)) print_addrs.push(bind_addr.clone())
} }
} }
} }
bind_addrs.sort_unstable(); print_addrs.sort_unstable();
let urls = bind_addrs Ok((new_addrs, print_addrs))
.into_iter() }
fn interface_addrs() -> Result<(Vec<BindAddr>, Vec<BindAddr>)> {
let (mut ipv4_addrs, mut ipv6_addrs) = (vec![], vec![]);
let ifaces =
if_addrs::get_if_addrs().with_context(|| "Failed to get local interface addresses")?;
for iface in ifaces.into_iter() {
let ip = iface.ip();
if ip.is_ipv4() {
ipv4_addrs.push(BindAddr::Address(ip))
}
if ip.is_ipv6() {
ipv6_addrs.push(BindAddr::Address(ip))
}
}
Ok((ipv4_addrs, ipv6_addrs))
}
fn print_listening(args: &Args, print_addrs: &[BindAddr]) -> Result<String> {
let mut output = String::new();
let urls = print_addrs
.iter()
.map(|bind_addr| match bind_addr { .map(|bind_addr| match bind_addr {
BindAddr::Address(addr) => { BindAddr::Address(addr) => {
let addr = match addr { let addr = match addr {

View File

@@ -35,7 +35,7 @@ use std::collections::HashMap;
use std::fs::Metadata; use std::fs::Metadata;
use std::io::SeekFrom; use std::io::SeekFrom;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::{Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::sync::atomic::{self, AtomicBool}; use std::sync::atomic::{self, AtomicBool};
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
@@ -71,7 +71,7 @@ pub struct Server {
impl Server { impl Server {
pub fn init(args: Args, running: Arc<AtomicBool>) -> Result<Self> { pub fn init(args: Args, running: Arc<AtomicBool>) -> Result<Self> {
let assets_prefix = format!("{}__dufs_v{}_", args.uri_prefix, env!("CARGO_PKG_VERSION")); let assets_prefix = format!("__dufs_v{}__/", env!("CARGO_PKG_VERSION"));
let single_file_req_paths = if args.path_is_file { let single_file_req_paths = if args.path_is_file {
vec![ vec![
args.uri_prefix.to_string(), args.uri_prefix.to_string(),
@@ -144,19 +144,23 @@ impl Server {
let headers = req.headers(); let headers = req.headers();
let method = req.method().clone(); let method = req.method().clone();
if method == Method::GET && self.handle_assets(req_path, headers, &mut res).await? {
return Ok(res);
}
let authorization = headers.get(AUTHORIZATION);
let relative_path = match self.resolve_path(req_path) { let relative_path = match self.resolve_path(req_path) {
Some(v) => v, Some(v) => v,
None => { None => {
status_forbid(&mut res); status_bad_request(&mut res, "Invalid Path");
return Ok(res); return Ok(res);
} }
}; };
if method == Method::GET
&& self
.handle_assets(&relative_path, headers, &mut res)
.await?
{
return Ok(res);
}
let authorization = headers.get(AUTHORIZATION);
let guard = self.args.auth.guard(&relative_path, &method, authorization); let guard = self.args.auth.guard(&relative_path, &method, authorization);
let (user, access_paths) = match guard { let (user, access_paths) = match guard {
@@ -298,10 +302,10 @@ impl Server {
} }
} else if is_file { } else if is_file {
if query_params.contains_key("edit") { if query_params.contains_key("edit") {
self.handle_deal_file(path, DataKind::Edit, head_only, user, &mut res) self.handle_edit_file(path, DataKind::Edit, head_only, user, &mut res)
.await?; .await?;
} else if query_params.contains_key("view") { } else if query_params.contains_key("view") {
self.handle_deal_file(path, DataKind::View, head_only, user, &mut res) self.handle_edit_file(path, DataKind::View, head_only, user, &mut res)
.await?; .await?;
} else { } else {
self.handle_send_file(path, headers, head_only, &mut res) self.handle_send_file(path, headers, head_only, &mut res)
@@ -375,7 +379,7 @@ impl Server {
"PROPFIND" => { "PROPFIND" => {
if is_dir { if is_dir {
let access_paths = let access_paths =
if access_paths.perm().inherit() && authorization.is_none() { if access_paths.perm().indexonly() && authorization.is_none() {
// see https://github.com/sigoden/dufs/issues/229 // see https://github.com/sigoden/dufs/issues/229
AccessPaths::new(AccessPerm::ReadOnly) AccessPaths::new(AccessPerm::ReadOnly)
} else { } else {
@@ -623,7 +627,7 @@ impl Server {
) -> Result<()> { ) -> Result<()> {
let (mut writer, reader) = tokio::io::duplex(BUF_SIZE); let (mut writer, reader) = tokio::io::duplex(BUF_SIZE);
let filename = try_get_file_name(path)?; let filename = try_get_file_name(path)?;
set_content_diposition(res, false, &format!("{}.zip", filename))?; set_content_disposition(res, false, &format!("{}.zip", filename))?;
res.headers_mut() res.headers_mut()
.insert("content-type", HeaderValue::from_static("application/zip")); .insert("content-type", HeaderValue::from_static("application/zip"));
if head_only { if head_only {
@@ -713,7 +717,12 @@ impl Server {
match self.args.assets.as_ref() { match self.args.assets.as_ref() {
Some(assets_path) => { Some(assets_path) => {
let path = assets_path.join(name); let path = assets_path.join(name);
self.handle_send_file(&path, headers, false, res).await?; if path.exists() {
self.handle_send_file(&path, headers, false, res).await?;
} else {
status_not_found(res);
return Ok(true);
}
} }
None => match name { None => match name {
"index.js" => { "index.js" => {
@@ -811,7 +820,7 @@ impl Server {
); );
let filename = try_get_file_name(path)?; let filename = try_get_file_name(path)?;
set_content_diposition(res, true, filename)?; set_content_disposition(res, true, filename)?;
res.headers_mut().typed_insert(AcceptRanges::bytes()); res.headers_mut().typed_insert(AcceptRanges::bytes());
@@ -860,7 +869,7 @@ impl Server {
Ok(()) Ok(())
} }
async fn handle_deal_file( async fn handle_edit_file(
&self, &self,
path: &Path, path: &Path,
kind: DataKind, kind: DataKind,
@@ -892,7 +901,10 @@ impl Server {
.typed_insert(ContentType::from(mime_guess::mime::TEXT_HTML_UTF_8)); .typed_insert(ContentType::from(mime_guess::mime::TEXT_HTML_UTF_8));
let output = self let output = self
.html .html
.replace("__ASSETS_PREFIX__", &self.assets_prefix) .replace(
"__ASSETS_PREFIX__",
&format!("{}{}", self.args.uri_prefix, self.assets_prefix),
)
.replace("__INDEX_DATA__", &serde_json::to_string(&data)?); .replace("__INDEX_DATA__", &serde_json::to_string(&data)?);
res.headers_mut() res.headers_mut()
.typed_insert(ContentLength(output.as_bytes().len() as u64)); .typed_insert(ContentLength(output.as_bytes().len() as u64));
@@ -1117,7 +1129,10 @@ impl Server {
res.headers_mut() res.headers_mut()
.typed_insert(ContentType::from(mime_guess::mime::TEXT_HTML_UTF_8)); .typed_insert(ContentType::from(mime_guess::mime::TEXT_HTML_UTF_8));
self.html self.html
.replace("__ASSETS_PREFIX__", &self.assets_prefix) .replace(
"__ASSETS_PREFIX__",
&format!("{}{}", self.args.uri_prefix, self.assets_prefix),
)
.replace("__INDEX_DATA__", &serde_json::to_string(&data)?) .replace("__INDEX_DATA__", &serde_json::to_string(&data)?)
}; };
res.headers_mut() res.headers_mut()
@@ -1153,18 +1168,13 @@ impl Server {
fn extract_dest(&self, req: &Request, res: &mut Response) -> Option<PathBuf> { fn extract_dest(&self, req: &Request, res: &mut Response) -> Option<PathBuf> {
let headers = req.headers(); let headers = req.headers();
let dest_path = match self.extract_destination_header(headers) { let dest_path = match self
.extract_destination_header(headers)
.and_then(|dest| self.resolve_path(&dest))
{
Some(dest) => dest, Some(dest) => dest,
None => { None => {
*res.status_mut() = StatusCode::BAD_REQUEST; status_bad_request(res, "Invalid Destination");
return None;
}
};
let relative_path = match self.resolve_path(&dest_path) {
Some(v) => v,
None => {
*res.status_mut() = StatusCode::BAD_REQUEST;
return None; return None;
} }
}; };
@@ -1173,7 +1183,7 @@ impl Server {
let guard = self let guard = self
.args .args
.auth .auth
.guard(&relative_path, req.method(), authorization); .guard(&dest_path, req.method(), authorization);
match guard { match guard {
(_, Some(_)) => {} (_, Some(_)) => {}
@@ -1183,7 +1193,7 @@ impl Server {
} }
}; };
let dest = match self.join_path(&relative_path) { let dest = match self.join_path(&dest_path) {
Some(dest) => dest, Some(dest) => dest,
None => { None => {
*res.status_mut() = StatusCode::BAD_REQUEST; *res.status_mut() = StatusCode::BAD_REQUEST;
@@ -1201,13 +1211,30 @@ impl Server {
} }
fn resolve_path(&self, path: &str) -> Option<String> { fn resolve_path(&self, path: &str) -> Option<String> {
let path = path.trim_matches('/');
let path = decode_uri(path)?; let path = decode_uri(path)?;
let prefix = self.args.path_prefix.as_str(); let path = path.trim_matches('/');
if prefix == "/" { let mut parts = vec![];
return Some(path.to_string()); for comp in Path::new(path).components() {
if let Component::Normal(v) = comp {
let v = v.to_string_lossy();
if cfg!(windows) {
let chars: Vec<char> = v.chars().collect();
if chars.len() == 2 && chars[1] == ':' && chars[0].is_ascii_alphabetic() {
return None;
}
}
parts.push(v);
} else {
return None;
}
} }
path.strip_prefix(prefix.trim_start_matches('/')) let new_path = parts.join("/");
let path_prefix = self.args.path_prefix.as_str();
if path_prefix.is_empty() {
return Some(new_path);
}
new_path
.strip_prefix(path_prefix.trim_start_matches('/'))
.map(|v| v.trim_matches('/').to_string()) .map(|v| v.trim_matches('/').to_string())
} }
@@ -1230,7 +1257,7 @@ impl Server {
access_paths: AccessPaths, access_paths: AccessPaths,
) -> Result<Vec<PathItem>> { ) -> Result<Vec<PathItem>> {
let mut paths: Vec<PathItem> = vec![]; let mut paths: Vec<PathItem> = vec![];
if access_paths.perm().inherit() { if access_paths.perm().indexonly() {
for name in access_paths.child_names() { for name in access_paths.child_names() {
let entry_path = entry_path.join(name); let entry_path = entry_path.join(name);
self.add_pathitem(&mut paths, base_path, &entry_path).await; self.add_pathitem(&mut paths, base_path, &entry_path).await;
@@ -1599,7 +1626,7 @@ fn status_bad_request(res: &mut Response, body: &str) {
} }
} }
fn set_content_diposition(res: &mut Response, inline: bool, filename: &str) -> Result<()> { fn set_content_disposition(res: &mut Response, inline: bool, filename: &str) -> Result<()> {
let kind = if inline { "inline" } else { "attachment" }; let kind = if inline { "inline" } else { "attachment" };
let filename: String = filename let filename: String = filename
.chars() .chars()
@@ -1682,7 +1709,7 @@ fn parse_upload_offset(headers: &HeaderMap<HeaderValue>, size: u64) -> Result<Op
Some(v) => v, Some(v) => v,
None => return Ok(None), None => return Ok(None),
}; };
let err = || anyhow!("Invalid X-Updage-Range header"); let err = || anyhow!("Invalid X-Update-Range Header");
let value = value.to_str().map_err(|_| err())?; let value = value.to_str().map_err(|_| err())?;
if value == "append" { if value == "append" {
return Ok(Some(size)); return Ok(Some(size));

View File

@@ -11,10 +11,11 @@ use std::process::{Command, Stdio};
fn assets(server: TestServer) -> Result<(), Error> { fn assets(server: TestServer) -> Result<(), Error> {
let ver = env!("CARGO_PKG_VERSION"); let ver = env!("CARGO_PKG_VERSION");
let resp = reqwest::blocking::get(server.url())?; let resp = reqwest::blocking::get(server.url())?;
let index_js = format!("/__dufs_v{ver}_index.js"); let index_js = format!("/__dufs_v{ver}__/index.js");
let index_css = format!("/__dufs_v{ver}_index.css"); let index_css = format!("/__dufs_v{ver}__/index.css");
let favicon_ico = format!("/__dufs_v{ver}_favicon.ico"); let favicon_ico = format!("/__dufs_v{ver}__/favicon.ico");
let text = resp.text()?; let text = resp.text()?;
println!("{text}");
assert!(text.contains(&format!(r#"href="{index_css}""#))); assert!(text.contains(&format!(r#"href="{index_css}""#)));
assert!(text.contains(&format!(r#"href="{favicon_ico}""#))); assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
assert!(text.contains(&format!(r#"src="{index_js}""#))); assert!(text.contains(&format!(r#"src="{index_js}""#)));
@@ -24,7 +25,7 @@ fn assets(server: TestServer) -> Result<(), Error> {
#[rstest] #[rstest]
fn asset_js(server: TestServer) -> Result<(), Error> { fn asset_js(server: TestServer) -> Result<(), Error> {
let url = format!( let url = format!(
"{}__dufs_v{}_index.js", "{}__dufs_v{}__/index.js",
server.url(), server.url(),
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
); );
@@ -40,7 +41,7 @@ fn asset_js(server: TestServer) -> Result<(), Error> {
#[rstest] #[rstest]
fn asset_css(server: TestServer) -> Result<(), Error> { fn asset_css(server: TestServer) -> Result<(), Error> {
let url = format!( let url = format!(
"{}__dufs_v{}_index.css", "{}__dufs_v{}__/index.css",
server.url(), server.url(),
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
); );
@@ -56,7 +57,7 @@ fn asset_css(server: TestServer) -> Result<(), Error> {
#[rstest] #[rstest]
fn asset_ico(server: TestServer) -> Result<(), Error> { fn asset_ico(server: TestServer) -> Result<(), Error> {
let url = format!( let url = format!(
"{}__dufs_v{}_favicon.ico", "{}__dufs_v{}__/favicon.ico",
server.url(), server.url(),
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
); );
@@ -70,9 +71,9 @@ fn asset_ico(server: TestServer) -> Result<(), Error> {
fn assets_with_prefix(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> { fn assets_with_prefix(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> {
let ver = env!("CARGO_PKG_VERSION"); let ver = env!("CARGO_PKG_VERSION");
let resp = reqwest::blocking::get(format!("{}xyz/", server.url()))?; let resp = reqwest::blocking::get(format!("{}xyz/", server.url()))?;
let index_js = format!("/xyz/__dufs_v{ver}_index.js"); let index_js = format!("/xyz/__dufs_v{ver}__/index.js");
let index_css = format!("/xyz/__dufs_v{ver}_index.css"); let index_css = format!("/xyz/__dufs_v{ver}__/index.css");
let favicon_ico = format!("/xyz/__dufs_v{ver}_favicon.ico"); let favicon_ico = format!("/xyz/__dufs_v{ver}__/favicon.ico");
let text = resp.text()?; let text = resp.text()?;
assert!(text.contains(&format!(r#"href="{index_css}""#))); assert!(text.contains(&format!(r#"href="{index_css}""#)));
assert!(text.contains(&format!(r#"href="{favicon_ico}""#))); assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
@@ -85,7 +86,7 @@ fn asset_js_with_prefix(
#[with(&["--path-prefix", "xyz"])] server: TestServer, #[with(&["--path-prefix", "xyz"])] server: TestServer,
) -> Result<(), Error> { ) -> Result<(), Error> {
let url = format!( let url = format!(
"{}xyz/__dufs_v{}_index.js", "{}xyz/__dufs_v{}__/index.js",
server.url(), server.url(),
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
); );
@@ -114,7 +115,7 @@ fn assets_override(tmpdir: TempDir, port: u16) -> Result<(), Error> {
let url = format!("http://localhost:{port}"); let url = format!("http://localhost:{port}");
let resp = reqwest::blocking::get(&url)?; let resp = reqwest::blocking::get(&url)?;
assert!(resp.text()?.starts_with(&format!( assert!(resp.text()?.starts_with(&format!(
"/__dufs_v{}_index.js;DATA", "/__dufs_v{}__/index.js;DATA",
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
))); )));
let resp = reqwest::blocking::get(&url)?; let resp = reqwest::blocking::get(&url)?;

View File

@@ -39,6 +39,25 @@ fn auth(#[case] server: TestServer, #[case] user: &str, #[case] pass: &str) -> R
Ok(()) Ok(())
} }
#[rstest]
fn invalid_auth(
#[with(&["-a", "user:pass@/:rw", "-a", "@/", "-A"])] server: TestServer,
) -> Result<(), Error> {
let resp = fetch!(b"GET", server.url())
.basic_auth("user", Some("-"))
.send()?;
assert_eq!(resp.status(), 401);
let resp = fetch!(b"GET", server.url())
.basic_auth("-", Some("pass"))
.send()?;
assert_eq!(resp.status(), 401);
let resp = fetch!(b"GET", server.url())
.header("Authorization", "Basic Og==")
.send()?;
assert_eq!(resp.status(), 401);
Ok(())
}
const HASHED_PASSWORD_AUTH: &str = "user:$6$gQxZwKyWn/ZmWEA2$4uV7KKMnSUnET2BtWTj/9T5.Jq3h/MdkOlnIl5hdlTxDZ4MZKmJ.kl6C.NL9xnNPqC4lVHC1vuI0E5cLpTJX81@/:rw"; // user:pass const HASHED_PASSWORD_AUTH: &str = "user:$6$gQxZwKyWn/ZmWEA2$4uV7KKMnSUnET2BtWTj/9T5.Jq3h/MdkOlnIl5hdlTxDZ4MZKmJ.kl6C.NL9xnNPqC4lVHC1vuI0E5cLpTJX81@/:rw"; // user:pass
#[rstest] #[rstest]
@@ -144,23 +163,6 @@ fn auth_readonly(
Ok(()) Ok(())
} }
#[rstest]
fn auth_forbidden(
#[with(&["--auth", "user:pass@/:rw,/dir1:-", "-A"])] server: TestServer,
) -> Result<(), Error> {
let url = format!("{}file1", server.url());
let resp = fetch!(b"PUT", &url)
.body(b"abc".to_vec())
.send_with_digest_auth("user", "pass")?;
assert_eq!(resp.status(), 201);
let url = format!("{}dir1/file1", server.url());
let resp = fetch!(b"PUT", &url)
.body(b"abc".to_vec())
.send_with_digest_auth("user", "pass")?;
assert_eq!(resp.status(), 403);
Ok(())
}
#[rstest] #[rstest]
fn auth_nest( fn auth_nest(
#[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "--auth", "user3:pass3@/dir1:rw", "-A"])] #[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "--auth", "user3:pass3@/dir1:rw", "-A"])]

View File

@@ -59,7 +59,7 @@ fn hidden_search_dir(#[case] server: TestServer, #[case] exist: bool) -> Result<
#[rstest] #[rstest]
#[case(server(&["--hidden", "hidden/"]), "dir4/", 1)] #[case(server(&["--hidden", "hidden/"]), "dir4/", 1)]
#[case(server(&["--hidden", "hidden"]), "dir4/", 0)] #[case(server(&["--hidden", "hidden"]), "dir4/", 0)]
fn hidden_dir_noly( fn hidden_dir_only(
#[case] server: TestServer, #[case] server: TestServer,
#[case] dir: &str, #[case] dir: &str,
#[case] count: usize, #[case] count: usize,

View File

@@ -53,7 +53,7 @@ fn path_prefix_single_file(tmpdir: TempDir, port: u16, #[case] file: &str) -> Re
let resp = reqwest::blocking::get(format!("http://localhost:{port}/xyz/index.html"))?; let resp = reqwest::blocking::get(format!("http://localhost:{port}/xyz/index.html"))?;
assert_eq!(resp.text()?, "This is index.html"); assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{port}"))?; let resp = reqwest::blocking::get(format!("http://localhost:{port}"))?;
assert_eq!(resp.status(), 403); assert_eq!(resp.status(), 400);
child.kill()?; child.kill()?;
Ok(()) Ok(())

View File

@@ -49,7 +49,7 @@ fn propfind_404(server: TestServer) -> Result<(), Error> {
#[rstest] #[rstest]
fn propfind_double_slash(server: TestServer) -> Result<(), Error> { fn propfind_double_slash(server: TestServer) -> Result<(), Error> {
let resp = fetch!(b"PROPFIND", format!("{}/", server.url())).send()?; let resp = fetch!(b"PROPFIND", server.url()).send()?;
assert_eq!(resp.status(), 207); assert_eq!(resp.status(), 207);
Ok(()) Ok(())
} }