copyparty 1.11.1__tar.gz → 1.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {copyparty-1.11.1 → copyparty-1.12.0}/PKG-INFO +28 -7
- {copyparty-1.11.1 → copyparty-1.12.0}/README.md +27 -6
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/__init__.py +0 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/__main__.py +26 -31
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/__version__.py +3 -3
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/authsrv.py +41 -23
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/ftpd.py +1 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/httpcli.py +112 -28
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/mtag.py +1 -2
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/star.py +4 -2
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/sutil.py +6 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/svchub.py +26 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/szip.py +5 -3
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/tftpd.py +3 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/th_cli.py +1 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/th_srv.py +48 -6
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/up2k.py +1 -1
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/util.py +18 -11
- copyparty-1.12.0/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/browser.css.gz +0 -0
- copyparty-1.12.0/copyparty/web/browser.js.gz +0 -0
- copyparty-1.12.0/copyparty/web/deps/busy.mp3.gz +0 -0
- copyparty-1.12.0/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/ui.css.gz +0 -0
- copyparty-1.12.0/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.12.0/copyparty/web/util.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/PKG-INFO +28 -7
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/SOURCES.txt +1 -0
- copyparty-1.11.1/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.11.1/copyparty/web/browser.js.gz +0 -0
- copyparty-1.11.1/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.11.1/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.11.1/copyparty/web/util.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/LICENSE +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/bos/bos.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/bos/path.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/broker_mp.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/broker_thr.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/broker_util.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/cert.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/cfg.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/dxml.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/fsutil.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/httpconn.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/httpsrv.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/ico.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/mdns.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/metrics.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/multicast.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/pwhash.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/res/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/smbd.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/ssdp.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/u2idx.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/browser.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/browser2.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/cf.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/md.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/mde.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/msg.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/splash.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/svcs.html +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/pyproject.toml +0 -0
- {copyparty-1.11.1 → copyparty-1.12.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.12.0
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
6
6
|
License: MIT
|
@@ -148,6 +148,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
148
148
|
* [gotchas](#gotchas) - behavior that might be unexpected
|
149
149
|
* [cors](#cors) - cross-site request config
|
150
150
|
* [filekeys](#filekeys) - prevent filename bruteforcing
|
151
|
+
* [dirkeys](#dirkeys) - share specific folders in a volume
|
151
152
|
* [password hashing](#password-hashing) - you can hash passwords
|
152
153
|
* [https](#https) - both HTTP and HTTPS are accepted
|
153
154
|
* [recovering from crashes](#recovering-from-crashes)
|
@@ -253,7 +254,7 @@ firewall-cmd --reload
|
|
253
254
|
* browser
|
254
255
|
* ☑ [navpane](#navpane) (directory tree sidebar)
|
255
256
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
256
|
-
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus transcoding)
|
257
|
+
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
257
258
|
* ☑ image gallery with webm player
|
258
259
|
* ☑ textfile browser with syntax hilighting
|
259
260
|
* ☑ [thumbnails](#thumbnails)
|
@@ -641,7 +642,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
641
642
|
|
642
643
|

|
643
644
|
|
644
|
-
cool trick: download a folder by appending url-params `?tar&opus` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus before they're added to the archive
|
645
|
+
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
645
646
|
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
646
647
|
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
|
647
648
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
@@ -832,9 +833,9 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
832
833
|
* `[loop]` keeps looping the folder
|
833
834
|
* `[next]` plays into the next folder
|
834
835
|
* "transcode":
|
835
|
-
* `[flac]` converts `flac` and `wav` files into opus
|
836
|
-
* `[aac]` converts `aac` and `m4a` files into opus
|
837
|
-
* `[oth]` converts all other known formats into opus
|
836
|
+
* `[flac]` converts `flac` and `wav` files into opus (if supported by browser) or mp3
|
837
|
+
* `[aac]` converts `aac` and `m4a` files into opus (if supported by browser) or mp3
|
838
|
+
* `[oth]` converts all other known formats into opus (if supported by browser) or mp3
|
838
839
|
* `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk`
|
839
840
|
* "tint" reduces the contrast of the playback bar
|
840
841
|
|
@@ -1345,6 +1346,8 @@ you may experience poor upload performance this way, but that can sometimes be f
|
|
1345
1346
|
|
1346
1347
|
someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
|
1347
1348
|
|
1349
|
+
you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
|
1350
|
+
|
1348
1351
|
|
1349
1352
|
## hiding from google
|
1350
1353
|
|
@@ -1794,6 +1797,7 @@ below are some tweaks roughly ordered by usefulness:
|
|
1794
1797
|
* `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
|
1795
1798
|
* and also makes thumbnails load faster, regardless of e2d/e2t
|
1796
1799
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
1800
|
+
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
1797
1801
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
1798
1802
|
* `-j0` enables multiprocessing (actual multithreading), can reduce latency to `20+80/numCores` percent and generally improve performance in cpu-intensive workloads, for example:
|
1799
1803
|
* lots of connections (many users or heavy clients)
|
@@ -1890,12 +1894,29 @@ cors can be configured with `--acao` and `--acam`, or the protections entirely d
|
|
1890
1894
|
|
1891
1895
|
prevent filename bruteforcing
|
1892
1896
|
|
1893
|
-
volflag `
|
1897
|
+
volflag `fk` generates filekeys (per-file accesskeys) for all files; users which have full read-access (permission `r`) will then see URLs with the correct filekey `?k=...` appended to the end, and `g` users must provide that URL including the correct key to avoid a 404
|
1894
1898
|
|
1895
1899
|
by default, filekeys are generated based on salt (`--fk-salt`) + filesystem-path + file-size + inode (if not windows); add volflag `fka` to generate slightly weaker filekeys which will not be invalidated if the file is edited (only salt + path)
|
1896
1900
|
|
1897
1901
|
permissions `wG` (write + upget) lets users upload files and receive their own filekeys, still without being able to see other uploads
|
1898
1902
|
|
1903
|
+
### dirkeys
|
1904
|
+
|
1905
|
+
share specific folders in a volume without giving away full read-access to the rest -- the visitor only needs the `g` (get) permission to view the link
|
1906
|
+
|
1907
|
+
volflag `dk` generates dirkeys (per-directory accesskeys) for all folders, granting read-access to that folder; by default only that folder itself, no subfolders
|
1908
|
+
|
1909
|
+
volflag `dky` disables the actual key-check, meaning anyone can see the contents of a folder where they have `g` access, but not its subdirectories
|
1910
|
+
|
1911
|
+
* `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
|
1912
|
+
|
1913
|
+
volflag `dks` lets people enter subfolders as well, and also enables download-as-zip/tar
|
1914
|
+
|
1915
|
+
dirkeys are generated based on another salt (`--dk-salt`) + filesystem-path and have a few limitations:
|
1916
|
+
* the key does not change if the contents of the folder is modified
|
1917
|
+
* if you need a new dirkey, either change the salt or rename the folder
|
1918
|
+
* linking to a textfile (so it opens in the textfile viewer) is not possible if recipient doesn't have read-access
|
1919
|
+
|
1899
1920
|
|
1900
1921
|
## password hashing
|
1901
1922
|
|
@@ -94,6 +94,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
94
94
|
* [gotchas](#gotchas) - behavior that might be unexpected
|
95
95
|
* [cors](#cors) - cross-site request config
|
96
96
|
* [filekeys](#filekeys) - prevent filename bruteforcing
|
97
|
+
* [dirkeys](#dirkeys) - share specific folders in a volume
|
97
98
|
* [password hashing](#password-hashing) - you can hash passwords
|
98
99
|
* [https](#https) - both HTTP and HTTPS are accepted
|
99
100
|
* [recovering from crashes](#recovering-from-crashes)
|
@@ -199,7 +200,7 @@ firewall-cmd --reload
|
|
199
200
|
* browser
|
200
201
|
* ☑ [navpane](#navpane) (directory tree sidebar)
|
201
202
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
202
|
-
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus transcoding)
|
203
|
+
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
203
204
|
* ☑ image gallery with webm player
|
204
205
|
* ☑ textfile browser with syntax hilighting
|
205
206
|
* ☑ [thumbnails](#thumbnails)
|
@@ -587,7 +588,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
587
588
|
|
588
589
|

|
589
590
|
|
590
|
-
cool trick: download a folder by appending url-params `?tar&opus` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus before they're added to the archive
|
591
|
+
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
591
592
|
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
592
593
|
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
|
593
594
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
@@ -778,9 +779,9 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
778
779
|
* `[loop]` keeps looping the folder
|
779
780
|
* `[next]` plays into the next folder
|
780
781
|
* "transcode":
|
781
|
-
* `[flac]` converts `flac` and `wav` files into opus
|
782
|
-
* `[aac]` converts `aac` and `m4a` files into opus
|
783
|
-
* `[oth]` converts all other known formats into opus
|
782
|
+
* `[flac]` converts `flac` and `wav` files into opus (if supported by browser) or mp3
|
783
|
+
* `[aac]` converts `aac` and `m4a` files into opus (if supported by browser) or mp3
|
784
|
+
* `[oth]` converts all other known formats into opus (if supported by browser) or mp3
|
784
785
|
* `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk`
|
785
786
|
* "tint" reduces the contrast of the playback bar
|
786
787
|
|
@@ -1291,6 +1292,8 @@ you may experience poor upload performance this way, but that can sometimes be f
|
|
1291
1292
|
|
1292
1293
|
someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
|
1293
1294
|
|
1295
|
+
you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
|
1296
|
+
|
1294
1297
|
|
1295
1298
|
## hiding from google
|
1296
1299
|
|
@@ -1740,6 +1743,7 @@ below are some tweaks roughly ordered by usefulness:
|
|
1740
1743
|
* `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
|
1741
1744
|
* and also makes thumbnails load faster, regardless of e2d/e2t
|
1742
1745
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
1746
|
+
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
1743
1747
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
1744
1748
|
* `-j0` enables multiprocessing (actual multithreading), can reduce latency to `20+80/numCores` percent and generally improve performance in cpu-intensive workloads, for example:
|
1745
1749
|
* lots of connections (many users or heavy clients)
|
@@ -1836,12 +1840,29 @@ cors can be configured with `--acao` and `--acam`, or the protections entirely d
|
|
1836
1840
|
|
1837
1841
|
prevent filename bruteforcing
|
1838
1842
|
|
1839
|
-
volflag `
|
1843
|
+
volflag `fk` generates filekeys (per-file accesskeys) for all files; users which have full read-access (permission `r`) will then see URLs with the correct filekey `?k=...` appended to the end, and `g` users must provide that URL including the correct key to avoid a 404
|
1840
1844
|
|
1841
1845
|
by default, filekeys are generated based on salt (`--fk-salt`) + filesystem-path + file-size + inode (if not windows); add volflag `fka` to generate slightly weaker filekeys which will not be invalidated if the file is edited (only salt + path)
|
1842
1846
|
|
1843
1847
|
permissions `wG` (write + upget) lets users upload files and receive their own filekeys, still without being able to see other uploads
|
1844
1848
|
|
1849
|
+
### dirkeys
|
1850
|
+
|
1851
|
+
share specific folders in a volume without giving away full read-access to the rest -- the visitor only needs the `g` (get) permission to view the link
|
1852
|
+
|
1853
|
+
volflag `dk` generates dirkeys (per-directory accesskeys) for all folders, granting read-access to that folder; by default only that folder itself, no subfolders
|
1854
|
+
|
1855
|
+
volflag `dky` disables the actual key-check, meaning anyone can see the contents of a folder where they have `g` access, but not its subdirectories
|
1856
|
+
|
1857
|
+
* `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
|
1858
|
+
|
1859
|
+
volflag `dks` lets people enter subfolders as well, and also enables download-as-zip/tar
|
1860
|
+
|
1861
|
+
dirkeys are generated based on another salt (`--dk-salt`) + filesystem-path and have a few limitations:
|
1862
|
+
* the key does not change if the contents of the folder is modified
|
1863
|
+
* if you need a new dirkey, either change the salt or rename the folder
|
1864
|
+
* linking to a textfile (so it opens in the textfile viewer) is not possible if recipient doesn't have read-access
|
1865
|
+
|
1845
1866
|
|
1846
1867
|
## password hashing
|
1847
1868
|
|
@@ -151,7 +151,8 @@ def warn(msg ) :
|
|
151
151
|
|
152
152
|
|
153
153
|
def init_E(EE ) :
|
154
|
-
#
|
154
|
+
# some cpython alternatives (such as pyoxidizer) can
|
155
|
+
# __init__ several times, so do expensive stuff here
|
155
156
|
|
156
157
|
E = EE # pylint: disable=redefined-outer-name
|
157
158
|
|
@@ -184,34 +185,9 @@ def init_E(EE ) :
|
|
184
185
|
|
185
186
|
raise Exception("could not find a writable path for config")
|
186
187
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
import tempfile
|
191
|
-
from importlib.resources import open_binary
|
192
|
-
|
193
|
-
td = tempfile.TemporaryDirectory(prefix="")
|
194
|
-
atexit.register(td.cleanup)
|
195
|
-
tdn = td.name
|
196
|
-
|
197
|
-
with open_binary("copyparty", "z.tar") as tgz:
|
198
|
-
with tarfile.open(fileobj=tgz) as tf:
|
199
|
-
try:
|
200
|
-
tf.extractall(tdn, filter="tar")
|
201
|
-
except TypeError:
|
202
|
-
tf.extractall(tdn) # nosec (archive is safe)
|
203
|
-
|
204
|
-
return tdn
|
205
|
-
|
206
|
-
try:
|
207
|
-
E.mod = os.path.dirname(os.path.realpath(__file__))
|
208
|
-
if E.mod.endswith("__init__"):
|
209
|
-
E.mod = os.path.dirname(E.mod)
|
210
|
-
except:
|
211
|
-
if not E.ox:
|
212
|
-
raise
|
213
|
-
|
214
|
-
E.mod = _unpack()
|
188
|
+
E.mod = os.path.dirname(os.path.realpath(__file__))
|
189
|
+
if E.mod.endswith("__init__"):
|
190
|
+
E.mod = os.path.dirname(E.mod)
|
215
191
|
|
216
192
|
if sys.platform == "win32":
|
217
193
|
bdir = os.environ.get("APPDATA") or os.environ.get("TEMP") or "."
|
@@ -268,6 +244,19 @@ def get_fk_salt() :
|
|
268
244
|
return ret.decode("utf-8")
|
269
245
|
|
270
246
|
|
247
|
+
def get_dk_salt() :
|
248
|
+
fp = os.path.join(E.cfg, "dk-salt.txt")
|
249
|
+
try:
|
250
|
+
with open(fp, "rb") as f:
|
251
|
+
ret = f.read().strip()
|
252
|
+
except:
|
253
|
+
ret = base64.b64encode(os.urandom(30))
|
254
|
+
with open(fp, "wb") as f:
|
255
|
+
f.write(ret + b"\n")
|
256
|
+
|
257
|
+
return ret.decode("utf-8")
|
258
|
+
|
259
|
+
|
271
260
|
def get_ah_salt() :
|
272
261
|
fp = os.path.join(E.cfg, "ah-salt.txt")
|
273
262
|
try:
|
@@ -863,6 +852,7 @@ def add_fs(ap):
|
|
863
852
|
ap2 = ap.add_argument_group("filesystem options")
|
864
853
|
rm_re_def = "5/0.1" if ANYWIN else "0/0"
|
865
854
|
ap2.add_argument("--rm-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be deleted because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=rm_retry)")
|
855
|
+
ap2.add_argument("--iobuf", metavar="BYTES", type=int, default=256*1024, help="file I/O buffer-size; if your volumes are on a network drive, try increasing to \033[32m524288\033[0m or even \033[32m4194304\033[0m (and let me know if that improves your performance)")
|
866
856
|
|
867
857
|
|
868
858
|
def add_upload(ap):
|
@@ -910,6 +900,7 @@ def add_network(ap):
|
|
910
900
|
ap2.add_argument("--freebind", action="store_true", help="allow listening on IPs which do not yet exist, for example if the network interfaces haven't finished going up. Only makes sense for IPs other than '0.0.0.0', '127.0.0.1', '::', and '::1'. May require running as root (unless net.ipv6.ip_nonlocal_bind)")
|
911
901
|
ap2.add_argument("--s-thead", metavar="SEC", type=int, default=120, help="socket timeout (read request header)")
|
912
902
|
ap2.add_argument("--s-tbody", metavar="SEC", type=float, default=186, help="socket timeout (read/write request/response bodies). Use 60 on fast servers (default is extremely safe). Disable with 0 if reverse-proxied for a 2%% speed boost")
|
903
|
+
ap2.add_argument("--s-rd-sz", metavar="B", type=int, default=256*1024, help="socket read size in bytes (indirectly affects filesystem writes; recommendation: keep equal-to or lower-than \033[33m--iobuf\033[0m)")
|
913
904
|
ap2.add_argument("--s-wr-sz", metavar="B", type=int, default=256*1024, help="socket write size in bytes")
|
914
905
|
ap2.add_argument("--s-wr-slp", metavar="SEC", type=float, default=0, help="debug: socket write delay in seconds")
|
915
906
|
ap2.add_argument("--rsp-slp", metavar="SEC", type=float, default=0, help="debug: response delay in seconds")
|
@@ -1123,13 +1114,14 @@ def add_safety(ap):
|
|
1123
1114
|
ap2.add_argument("--acam", metavar="V[,V]", type=u, default="GET,HEAD", help="Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like \033[33m--acao\033[0m's description)")
|
1124
1115
|
|
1125
1116
|
|
1126
|
-
def add_salt(ap, fk_salt, ah_salt):
|
1117
|
+
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
1127
1118
|
ap2 = ap.add_argument_group('salting options')
|
1128
1119
|
ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)")
|
1129
1120
|
ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)")
|
1130
1121
|
ap2.add_argument("--ah-gen", metavar="PW", type=u, default="", help="generate hashed password for \033[33mPW\033[0m, or read passwords from STDIN if \033[33mPW\033[0m is [\033[32m-\033[0m]")
|
1131
1122
|
ap2.add_argument("--ah-cli", action="store_true", help="launch an interactive shell which hashes passwords without ever storing or displaying the original passwords")
|
1132
1123
|
ap2.add_argument("--fk-salt", metavar="SALT", type=u, default=fk_salt, help="per-file accesskey salt; used to generate unpredictable URLs for hidden files")
|
1124
|
+
ap2.add_argument("--dk-salt", metavar="SALT", type=u, default=dk_salt, help="per-directory accesskey salt; used to generate unpredictable URLs to share folders with users who only have the 'get' permission")
|
1133
1125
|
ap2.add_argument("--warksalt", metavar="SALT", type=u, default="hunter2", help="up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do)")
|
1134
1126
|
|
1135
1127
|
|
@@ -1195,6 +1187,8 @@ def add_thumbnail(ap):
|
|
1195
1187
|
|
1196
1188
|
def add_transcoding(ap):
|
1197
1189
|
ap2 = ap.add_argument_group('transcoding options')
|
1190
|
+
ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable")
|
1191
|
+
ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable")
|
1198
1192
|
ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding")
|
1199
1193
|
ap2.add_argument("--no-bacode", action="store_true", help="disable batch audio transcoding by folder download (zip/tar)")
|
1200
1194
|
ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
|
@@ -1311,6 +1305,7 @@ def run_argparse(
|
|
1311
1305
|
cert_path = os.path.join(E.cfg, "cert.pem")
|
1312
1306
|
|
1313
1307
|
fk_salt = get_fk_salt()
|
1308
|
+
dk_salt = get_dk_salt()
|
1314
1309
|
ah_salt = get_ah_salt()
|
1315
1310
|
|
1316
1311
|
# alpine peaks at 5 threads for some reason,
|
@@ -1342,7 +1337,7 @@ def run_argparse(
|
|
1342
1337
|
add_tftp(ap)
|
1343
1338
|
add_smb(ap)
|
1344
1339
|
add_safety(ap)
|
1345
|
-
add_salt(ap, fk_salt, ah_salt)
|
1340
|
+
add_salt(ap, fk_salt, dk_salt, ah_salt)
|
1346
1341
|
add_optouts(ap)
|
1347
1342
|
add_shutdown(ap)
|
1348
1343
|
add_yolo(ap)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2024,
|
3
|
+
VERSION = (1, 12, 0)
|
4
|
+
CODENAME = "locksmith"
|
5
|
+
BUILD_DT = (2024, 4, 6)
|
6
6
|
|
7
7
|
S_VERSION = ".".join(map(str, VERSION))
|
8
8
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
@@ -548,7 +548,12 @@ class VFS(object):
|
|
548
548
|
# no vfs nodes in the list of real inodes
|
549
549
|
real = [x for x in real if x[0] not in self.nodes]
|
550
550
|
|
551
|
+
dbv = self.dbv or self
|
551
552
|
for name, vn2 in sorted(self.nodes.items()):
|
553
|
+
if vn2.dbv == dbv and self.flags.get("dk"):
|
554
|
+
virt_vis[name] = vn2
|
555
|
+
continue
|
556
|
+
|
552
557
|
ok = False
|
553
558
|
zx = vn2.axs
|
554
559
|
axs = [zx.uread, zx.uwrite, zx.umove, zx.udel, zx.uget]
|
@@ -1217,7 +1222,9 @@ class AuthSrv(object):
|
|
1217
1222
|
if un.startswith("@"):
|
1218
1223
|
grp = un[1:]
|
1219
1224
|
uns = [x[0] for x in un_gns.items() if grp in x[1]]
|
1220
|
-
if
|
1225
|
+
if grp == "${g}":
|
1226
|
+
unames.append(un)
|
1227
|
+
elif not uns and not self.args.idp_h_grp:
|
1221
1228
|
t = "group [%s] must be defined with --grp argument (or in a [groups] config section)"
|
1222
1229
|
raise CfgEx(t % (grp,))
|
1223
1230
|
|
@@ -1227,31 +1234,28 @@ class AuthSrv(object):
|
|
1227
1234
|
|
1228
1235
|
# unames may still contain ${u} and ${g} so now expand those;
|
1229
1236
|
un_gn = [(un, gn) for un, gns in un_gns.items() for gn in gns]
|
1230
|
-
if "*" not in un_gns:
|
1231
|
-
# need ("*","") to match "*" in unames
|
1232
|
-
un_gn.append(("*", ""))
|
1233
|
-
|
1234
|
-
for _, dst, vu, vg in vols:
|
1235
|
-
unames2 = set()
|
1236
|
-
for un, gn in un_gn:
|
1237
|
-
# if vu/vg (volume user/group) is non-null,
|
1238
|
-
# then each non-null value corresponds to
|
1239
|
-
# ${u}/${g}; consider this a filter to
|
1240
|
-
# apply to unames, as well as un_gn
|
1241
|
-
if (vu and vu != un) or (vg and vg != gn):
|
1242
|
-
continue
|
1243
1237
|
|
1244
|
-
|
1245
|
-
|
1246
|
-
uname = vu or un
|
1247
|
-
elif uname in ("${g}", "@${g}"):
|
1248
|
-
uname = vg or gn
|
1238
|
+
for src, dst, vu, vg in vols:
|
1239
|
+
unames2 = set(unames)
|
1249
1240
|
|
1250
|
-
|
1251
|
-
|
1241
|
+
if "${u}" in unames:
|
1242
|
+
if not vu:
|
1243
|
+
t = "cannot use ${u} in accs of volume [%s] because the volume url does not contain ${u}"
|
1244
|
+
raise CfgEx(t % (src,))
|
1245
|
+
unames2.add(vu)
|
1246
|
+
|
1247
|
+
if "@${g}" in unames:
|
1248
|
+
if not vg:
|
1249
|
+
t = "cannot use @${g} in accs of volume [%s] because the volume url does not contain @${g}"
|
1250
|
+
raise CfgEx(t % (src,))
|
1251
|
+
unames2.update([un for un, gn in un_gn if gn == vg])
|
1252
1252
|
|
1253
|
-
|
1254
|
-
|
1253
|
+
if "${g}" in unames:
|
1254
|
+
t = 'the accs of volume [%s] contains "${g}" but the only supported way of specifying that is "@${g}"'
|
1255
|
+
raise CfgEx(t % (src,))
|
1256
|
+
|
1257
|
+
unames2.discard("${u}")
|
1258
|
+
unames2.discard("@${g}")
|
1255
1259
|
|
1256
1260
|
self._read_vol_str(lvl, list(unames2), axs[dst])
|
1257
1261
|
|
@@ -1675,6 +1679,20 @@ class AuthSrv(object):
|
|
1675
1679
|
vol.flags["fk"] = int(fk) if fk is not True else 8
|
1676
1680
|
have_fk = True
|
1677
1681
|
|
1682
|
+
dk = vol.flags.get("dk")
|
1683
|
+
dks = vol.flags.get("dks")
|
1684
|
+
dky = vol.flags.get("dky")
|
1685
|
+
if dks is not None and dky is not None:
|
1686
|
+
t = "WARNING: volume /%s has both dks and dky enabled; this is too yolo and not permitted"
|
1687
|
+
raise Exception(t % (vol.vpath,))
|
1688
|
+
|
1689
|
+
if dks and not dk:
|
1690
|
+
dk = dks
|
1691
|
+
if dky and not dk:
|
1692
|
+
dk = dky
|
1693
|
+
if dk:
|
1694
|
+
vol.flags["dk"] = int(dk) if dk is not True else 8
|
1695
|
+
|
1678
1696
|
if have_fk and re.match(r"^[0-9\.]+$", self.args.fk_salt):
|
1679
1697
|
self.log("filekey salt: {}".format(self.args.fk_salt))
|
1680
1698
|
|
@@ -213,7 +213,7 @@ class FtpFs(AbstractedFS):
|
|
213
213
|
raise FSE("Cannot open existing file for writing")
|
214
214
|
|
215
215
|
self.validpath(ap)
|
216
|
-
return open(fsenc(ap), mode)
|
216
|
+
return open(fsenc(ap), mode, self.args.iobuf)
|
217
217
|
|
218
218
|
def chdir(self, path ) :
|
219
219
|
nwd = join(self.cwd, path)
|