copyparty 1.13.6__tar.gz → 1.13.7__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.
Files changed (117) hide show
  1. {copyparty-1.13.6 → copyparty-1.13.7}/PKG-INFO +56 -6
  2. {copyparty-1.13.6 → copyparty-1.13.7}/README.md +55 -5
  3. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/__main__.py +25 -7
  4. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/__version__.py +2 -2
  5. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/authsrv.py +9 -6
  6. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/cert.py +1 -1
  7. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/fsutil.py +3 -3
  8. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/ftpd.py +15 -2
  9. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/httpcli.py +221 -81
  10. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/httpconn.py +3 -0
  11. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/httpsrv.py +35 -11
  12. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/ico.py +1 -1
  13. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/mtag.py +15 -6
  14. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/pwhash.py +10 -0
  15. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/smbd.py +20 -2
  16. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/ssdp.py +3 -3
  17. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/dns.py +6 -0
  18. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/ifaddr/__init__.py +15 -1
  19. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/ifaddr/_shared.py +1 -0
  20. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/qrcodegen.py +6 -0
  21. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/sutil.py +1 -1
  22. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/svchub.py +72 -3
  23. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/szip.py +1 -3
  24. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/tcpsrv.py +60 -8
  25. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/tftpd.py +30 -4
  26. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/th_srv.py +22 -1
  27. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/u2idx.py +4 -1
  28. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/up2k.py +221 -93
  29. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/util.py +166 -31
  30. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/a/u2c.py +10 -3
  31. copyparty-1.13.7/copyparty/web/browser.css.gz +0 -0
  32. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/browser2.html +0 -1
  33. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/md.html +3 -0
  34. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/mde.html +3 -0
  35. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/msg.html +3 -0
  36. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/splash.html +3 -0
  37. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/svcs.html +3 -0
  38. copyparty-1.13.7/copyparty/web/up2k.js.gz +0 -0
  39. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/PKG-INFO +56 -6
  40. copyparty-1.13.6/copyparty/web/browser.css.gz +0 -0
  41. copyparty-1.13.6/copyparty/web/up2k.js.gz +0 -0
  42. {copyparty-1.13.6 → copyparty-1.13.7}/LICENSE +0 -0
  43. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/__init__.py +0 -0
  44. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/bos/__init__.py +0 -0
  45. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/bos/bos.py +0 -0
  46. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/bos/path.py +0 -0
  47. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/broker_mp.py +0 -0
  48. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/broker_mpw.py +0 -0
  49. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/broker_thr.py +0 -0
  50. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/broker_util.py +0 -0
  51. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/cfg.py +0 -0
  52. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/dxml.py +0 -0
  53. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/mdns.py +0 -0
  54. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/metrics.py +0 -0
  55. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/multicast.py +0 -0
  56. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/res/COPYING.txt +0 -0
  57. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/res/__init__.py +0 -0
  58. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/res/insecure.pem +0 -0
  59. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/star.py +0 -0
  60. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/__init__.py +0 -0
  61. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/__init__.py +0 -0
  62. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/bimap.py +0 -0
  63. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/bit.py +0 -0
  64. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/buffer.py +0 -0
  65. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/label.py +0 -0
  66. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/lex.py +0 -0
  67. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/dnslib/ranges.py +0 -0
  68. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/ifaddr/_posix.py +0 -0
  69. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/ifaddr/_win32.py +0 -0
  70. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/stolen/surrogateescape.py +0 -0
  71. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/th_cli.py +0 -0
  72. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/a/__init__.py +0 -0
  73. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/a/partyfuse.py +0 -0
  74. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/a/webdav-cfg.bat +0 -0
  75. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/baguettebox.js.gz +0 -0
  76. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/browser.html +0 -0
  77. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/browser.js.gz +0 -0
  78. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/cf.html +0 -0
  79. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dbg-audio.js.gz +0 -0
  80. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dd/2.png +0 -0
  81. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dd/3.png +0 -0
  82. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dd/4.png +0 -0
  83. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dd/5.png +0 -0
  84. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/dd/__init__.py +0 -0
  85. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/__init__.py +0 -0
  86. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/busy.mp3.gz +0 -0
  87. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/easymde.css.gz +0 -0
  88. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/easymde.js.gz +0 -0
  89. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/marked.js.gz +0 -0
  90. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/mini-fa.css.gz +0 -0
  91. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/mini-fa.woff +0 -0
  92. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/prism.css.gz +0 -0
  93. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/prism.js.gz +0 -0
  94. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/prismd.css.gz +0 -0
  95. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/scp.woff2 +0 -0
  96. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  97. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  98. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/md.css.gz +0 -0
  99. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/md.js.gz +0 -0
  100. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/md2.css.gz +0 -0
  101. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/md2.js.gz +0 -0
  102. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/mde.css.gz +0 -0
  103. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/mde.js.gz +0 -0
  104. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/msg.css.gz +0 -0
  105. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/splash.css.gz +0 -0
  106. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/splash.js.gz +0 -0
  107. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/svcs.js.gz +0 -0
  108. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/ui.css.gz +0 -0
  109. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/util.js.gz +0 -0
  110. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty/web/w.hash.js.gz +0 -0
  111. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/SOURCES.txt +0 -0
  112. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/dependency_links.txt +0 -0
  113. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/entry_points.txt +0 -0
  114. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/requires.txt +0 -0
  115. {copyparty-1.13.6 → copyparty-1.13.7}/copyparty.egg-info/top_level.txt +0 -0
  116. {copyparty-1.13.6 → copyparty-1.13.7}/pyproject.toml +0 -0
  117. {copyparty-1.13.6 → copyparty-1.13.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.13.6
3
+ Version: 1.13.7
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
@@ -139,6 +139,7 @@ turn almost any device into a file server with resumable uploads/downloads using
139
139
  * [prometheus](#prometheus) - metrics/stats can be enabled
140
140
  * [other extremely specific features](#other-extremely-specific-features) - you'll never find a use for these
141
141
  * [custom mimetypes](#custom-mimetypes) - change the association of a file extension
142
+ * [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
142
143
  * [packages](#packages) - the party might be closer than you think
143
144
  * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
144
145
  * [fedora package](#fedora-package) - does not exist yet
@@ -165,6 +166,7 @@ turn almost any device into a file server with resumable uploads/downloads using
165
166
  * [HTTP API](#HTTP-API) - see [devnotes](./docs/devnotes.md#http-api)
166
167
  * [dependencies](#dependencies) - mandatory deps
167
168
  * [optional dependencies](#optional-dependencies) - install these to enable bonus features
169
+ * [dependency chickenbits](#dependency-chickenbits) - prevent loading an optional dependency
168
170
  * [optional gpl stuff](#optional-gpl-stuff)
169
171
  * [sfx](#sfx) - the self-contained "binary" (recommended!)
170
172
  * [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
@@ -178,7 +180,7 @@ turn almost any device into a file server with resumable uploads/downloads using
178
180
 
179
181
  just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉
180
182
 
181
- * or install through pypi: `python3 -m pip install --user -U copyparty`
183
+ * or install through [pypi](https://pypi.org/project/copyparty/): `python3 -m pip install --user -U copyparty`
182
184
  * or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
183
185
  * or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
184
186
  * or if you are on android, [install copyparty in termux](#install-on-android)
@@ -248,7 +250,7 @@ firewall-cmd --reload
248
250
  also see [comparison to similar software](./docs/versus.md)
249
251
 
250
252
  * backend stuff
251
- * ☑ IPv6
253
+ * ☑ IPv6 + unix-sockets
252
254
  * ☑ [multiprocessing](#performance) (actual multithreading)
253
255
  * ☑ volumes (mountpoints)
254
256
  * ☑ [accounts](#accounts-and-volumes)
@@ -633,9 +635,6 @@ images with the following names (see `--th-covers`) become the thumbnail of the
633
635
  * the order is significant, so if both `cover.png` and `folder.jpg` exist in a folder, it will pick the first matching `--th-covers` entry (`folder.jpg`)
634
636
  * and, if you enable [file indexing](#file-indexing), it will also try those names as dotfiles (`.folder.jpg` and so), and then fallback on the first picture in the folder (if it has any pictures at all)
635
637
 
636
- in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked
637
- * indicated by the audio files having the ▶ icon instead of 💾
638
-
639
638
  enabling `multiselect` lets you click files to select them, and then shift-click another file for range-select
640
639
  * `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking
641
640
  * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
@@ -1514,6 +1513,8 @@ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatical
1514
1513
  * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
1515
1514
  * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
1516
1515
 
1516
+ for improved security (and a tiny performance boost) consider listening on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1`
1517
+
1517
1518
  example webserver configs:
1518
1519
 
1519
1520
  * [nginx config](contrib/nginx/copyparty.conf) -- entire domain/subdomain
@@ -1614,6 +1615,23 @@ in a config-file, this is the same as:
1614
1615
  run copyparty with `--mimes` to list all the default mappings
1615
1616
 
1616
1617
 
1618
+ ### feature chickenbits
1619
+
1620
+ buggy feature? rip it out by setting any of the following environment variables to disable its associated bell or whistle,
1621
+
1622
+ | env-var | what it does |
1623
+ | -------------------- | ------------ |
1624
+ | `PRTY_NO_IFADDR` | disable ip/nic discovery by poking into your OS with ctypes |
1625
+ | `PRTY_NO_IPV6` | disable some ipv6 support (should not be necessary since windows 2000) |
1626
+ | `PRTY_NO_LZMA` | disable streaming xz compression of incoming uploads |
1627
+ | `PRTY_NO_MP` | disable all use of the python `multiprocessing` module (actual multithreading, cpu-count for parsers/thumbnailers) |
1628
+ | `PRTY_NO_SQLITE` | disable all database-related functionality (file indexing, metadata indexing, most file deduplication logic) |
1629
+ | `PRTY_NO_TLS` | disable native HTTPS support; if you still want to accept HTTPS connections then TLS must now be terminated by a reverse-proxy |
1630
+ | `PRTY_NO_TPOKE` | disable systemd-tmpfilesd avoider |
1631
+
1632
+ example: `PRTY_NO_IFADDR=1 python3 copyparty-sfx.py`
1633
+
1634
+
1617
1635
  # packages
1618
1636
 
1619
1637
  the party might be closer than you think
@@ -1936,6 +1954,7 @@ some notes on hardening
1936
1954
  * cors doesn't work right otherwise
1937
1955
  * if you allow anonymous uploads or otherwise don't trust the contents of a volume, you can prevent XSS with volflag `nohtml`
1938
1956
  * this returns html documents as plaintext, and also disables markdown rendering
1957
+ * when running behind a reverse-proxy, listen on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1` for tighter access control (plus you get a tiny performance boost for free)
1939
1958
 
1940
1959
  safety profiles:
1941
1960
 
@@ -2100,6 +2119,37 @@ enable [smb](#smb-server) support (**not** recommended):
2100
2119
  `pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
2101
2120
 
2102
2121
 
2122
+ ### dependency chickenbits
2123
+
2124
+ prevent loading an optional dependency , for example if:
2125
+
2126
+ * you have an incompatible version installed and it causes problems
2127
+ * you just don't want copyparty to use it, maybe to save ram
2128
+
2129
+ set any of the following environment variables to disable its associated optional feature,
2130
+
2131
+ | env-var | what it does |
2132
+ | -------------------- | ------------ |
2133
+ | `PRTY_NO_ARGON2` | disable argon2-cffi password hashing |
2134
+ | `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
2135
+ | `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
2136
+ | `PRTY_NO_FFPROBE` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips, **metadata-scanning** must be handled by mutagen |
2137
+ | `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
2138
+ | `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
2139
+ | `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
2140
+ | `PRTY_NO_PIL_AVIF` | disable 3rd-party Pillow plugin for [AVIF support](https://pypi.org/project/pillow-avif-plugin/) |
2141
+ | `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/pyheif-pillow-opener/) |
2142
+ | `PRTY_NO_PIL_WEBP` | disable use of native webp support in Pillow |
2143
+ | `PRTY_NO_PSUTIL` | do not use [psutil](https://pypi.org/project/psutil/) for reaping stuck hooks and plugins on Windows |
2144
+ | `PRTY_NO_VIPS` | disable all [libvips](https://pypi.org/project/pyvips/)-based thumbnail support; will fallback to Pillow or ffmpeg |
2145
+
2146
+ example: `PRTY_NO_PIL=1 python3 copyparty-sfx.py`
2147
+
2148
+ * `PRTY_NO_PIL` saves ram
2149
+ * `PRTY_NO_VIPS` saves ram and startup time
2150
+ * python2.7 on windows: `PRTY_NO_FFMPEG` + `PRTY_NO_FFPROBE` saves startup time
2151
+
2152
+
2103
2153
  ## optional gpl stuff
2104
2154
 
2105
2155
  some bundled tools have copyleft dependencies, see [./bin/#mtag](bin/#mtag)
@@ -85,6 +85,7 @@ turn almost any device into a file server with resumable uploads/downloads using
85
85
  * [prometheus](#prometheus) - metrics/stats can be enabled
86
86
  * [other extremely specific features](#other-extremely-specific-features) - you'll never find a use for these
87
87
  * [custom mimetypes](#custom-mimetypes) - change the association of a file extension
88
+ * [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
88
89
  * [packages](#packages) - the party might be closer than you think
89
90
  * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
90
91
  * [fedora package](#fedora-package) - does not exist yet
@@ -111,6 +112,7 @@ turn almost any device into a file server with resumable uploads/downloads using
111
112
  * [HTTP API](#HTTP-API) - see [devnotes](./docs/devnotes.md#http-api)
112
113
  * [dependencies](#dependencies) - mandatory deps
113
114
  * [optional dependencies](#optional-dependencies) - install these to enable bonus features
115
+ * [dependency chickenbits](#dependency-chickenbits) - prevent loading an optional dependency
114
116
  * [optional gpl stuff](#optional-gpl-stuff)
115
117
  * [sfx](#sfx) - the self-contained "binary" (recommended!)
116
118
  * [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
@@ -124,7 +126,7 @@ turn almost any device into a file server with resumable uploads/downloads using
124
126
 
125
127
  just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉
126
128
 
127
- * or install through pypi: `python3 -m pip install --user -U copyparty`
129
+ * or install through [pypi](https://pypi.org/project/copyparty/): `python3 -m pip install --user -U copyparty`
128
130
  * or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
129
131
  * or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
130
132
  * or if you are on android, [install copyparty in termux](#install-on-android)
@@ -194,7 +196,7 @@ firewall-cmd --reload
194
196
  also see [comparison to similar software](./docs/versus.md)
195
197
 
196
198
  * backend stuff
197
- * ☑ IPv6
199
+ * ☑ IPv6 + unix-sockets
198
200
  * ☑ [multiprocessing](#performance) (actual multithreading)
199
201
  * ☑ volumes (mountpoints)
200
202
  * ☑ [accounts](#accounts-and-volumes)
@@ -579,9 +581,6 @@ images with the following names (see `--th-covers`) become the thumbnail of the
579
581
  * the order is significant, so if both `cover.png` and `folder.jpg` exist in a folder, it will pick the first matching `--th-covers` entry (`folder.jpg`)
580
582
  * and, if you enable [file indexing](#file-indexing), it will also try those names as dotfiles (`.folder.jpg` and so), and then fallback on the first picture in the folder (if it has any pictures at all)
581
583
 
582
- in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked
583
- * indicated by the audio files having the ▶ icon instead of 💾
584
-
585
584
  enabling `multiselect` lets you click files to select them, and then shift-click another file for range-select
586
585
  * `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking
587
586
  * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
@@ -1460,6 +1459,8 @@ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatical
1460
1459
  * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
1461
1460
  * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
1462
1461
 
1462
+ for improved security (and a tiny performance boost) consider listening on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1`
1463
+
1463
1464
  example webserver configs:
1464
1465
 
1465
1466
  * [nginx config](contrib/nginx/copyparty.conf) -- entire domain/subdomain
@@ -1560,6 +1561,23 @@ in a config-file, this is the same as:
1560
1561
  run copyparty with `--mimes` to list all the default mappings
1561
1562
 
1562
1563
 
1564
+ ### feature chickenbits
1565
+
1566
+ buggy feature? rip it out by setting any of the following environment variables to disable its associated bell or whistle,
1567
+
1568
+ | env-var | what it does |
1569
+ | -------------------- | ------------ |
1570
+ | `PRTY_NO_IFADDR` | disable ip/nic discovery by poking into your OS with ctypes |
1571
+ | `PRTY_NO_IPV6` | disable some ipv6 support (should not be necessary since windows 2000) |
1572
+ | `PRTY_NO_LZMA` | disable streaming xz compression of incoming uploads |
1573
+ | `PRTY_NO_MP` | disable all use of the python `multiprocessing` module (actual multithreading, cpu-count for parsers/thumbnailers) |
1574
+ | `PRTY_NO_SQLITE` | disable all database-related functionality (file indexing, metadata indexing, most file deduplication logic) |
1575
+ | `PRTY_NO_TLS` | disable native HTTPS support; if you still want to accept HTTPS connections then TLS must now be terminated by a reverse-proxy |
1576
+ | `PRTY_NO_TPOKE` | disable systemd-tmpfilesd avoider |
1577
+
1578
+ example: `PRTY_NO_IFADDR=1 python3 copyparty-sfx.py`
1579
+
1580
+
1563
1581
  # packages
1564
1582
 
1565
1583
  the party might be closer than you think
@@ -1882,6 +1900,7 @@ some notes on hardening
1882
1900
  * cors doesn't work right otherwise
1883
1901
  * if you allow anonymous uploads or otherwise don't trust the contents of a volume, you can prevent XSS with volflag `nohtml`
1884
1902
  * this returns html documents as plaintext, and also disables markdown rendering
1903
+ * when running behind a reverse-proxy, listen on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1` for tighter access control (plus you get a tiny performance boost for free)
1885
1904
 
1886
1905
  safety profiles:
1887
1906
 
@@ -2046,6 +2065,37 @@ enable [smb](#smb-server) support (**not** recommended):
2046
2065
  `pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
2047
2066
 
2048
2067
 
2068
+ ### dependency chickenbits
2069
+
2070
+ prevent loading an optional dependency , for example if:
2071
+
2072
+ * you have an incompatible version installed and it causes problems
2073
+ * you just don't want copyparty to use it, maybe to save ram
2074
+
2075
+ set any of the following environment variables to disable its associated optional feature,
2076
+
2077
+ | env-var | what it does |
2078
+ | -------------------- | ------------ |
2079
+ | `PRTY_NO_ARGON2` | disable argon2-cffi password hashing |
2080
+ | `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
2081
+ | `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
2082
+ | `PRTY_NO_FFPROBE` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips, **metadata-scanning** must be handled by mutagen |
2083
+ | `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
2084
+ | `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
2085
+ | `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
2086
+ | `PRTY_NO_PIL_AVIF` | disable 3rd-party Pillow plugin for [AVIF support](https://pypi.org/project/pillow-avif-plugin/) |
2087
+ | `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/pyheif-pillow-opener/) |
2088
+ | `PRTY_NO_PIL_WEBP` | disable use of native webp support in Pillow |
2089
+ | `PRTY_NO_PSUTIL` | do not use [psutil](https://pypi.org/project/psutil/) for reaping stuck hooks and plugins on Windows |
2090
+ | `PRTY_NO_VIPS` | disable all [libvips](https://pypi.org/project/pyvips/)-based thumbnail support; will fallback to Pillow or ffmpeg |
2091
+
2092
+ example: `PRTY_NO_PIL=1 python3 copyparty-sfx.py`
2093
+
2094
+ * `PRTY_NO_PIL` saves ram
2095
+ * `PRTY_NO_VIPS` saves ram and startup time
2096
+ * python2.7 on windows: `PRTY_NO_FFMPEG` + `PRTY_NO_FFPROBE` saves startup time
2097
+
2098
+
2049
2099
  ## optional gpl stuff
2050
2100
 
2051
2101
  some bundled tools have copyleft dependencies, see [./bin/#mtag](bin/#mtag)
@@ -61,7 +61,13 @@ from .util import (
61
61
  wrap,
62
62
  )
63
63
 
64
+ if PY2:
65
+ range = xrange # type: ignore
66
+
64
67
  try:
68
+ if os.environ.get("PRTY_NO_TLS"):
69
+ raise Exception()
70
+
65
71
  HAVE_SSL = True
66
72
  import ssl
67
73
  except:
@@ -338,7 +344,7 @@ def configure_ssl_ver(al ) :
338
344
  # oh man i love openssl
339
345
  # check this out
340
346
  # hold my beer
341
- assert ssl
347
+ assert ssl # type: ignore
342
348
  ptn = re.compile(r"^OP_NO_(TLS|SSL)v")
343
349
  sslver = terse_sslver(al.ssl_ver).split(",")
344
350
  flags = [k for k in ssl.__dict__ if ptn.match(k)]
@@ -372,7 +378,7 @@ def configure_ssl_ver(al ) :
372
378
 
373
379
 
374
380
  def configure_ssl_ciphers(al ) :
375
- assert ssl
381
+ assert ssl # type: ignore
376
382
  ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
377
383
  if al.ssl_ver:
378
384
  ctx.options &= ~al.ssl_flags_en
@@ -485,6 +491,9 @@ def disable_quickedit() :
485
491
 
486
492
 
487
493
  def sfx_tpoke(top ):
494
+ if os.environ.get("PRTY_NO_TPOKE"):
495
+ return
496
+
488
497
  files = [top] + [
489
498
  os.path.join(dp, p) for dp, dd, df in os.walk(top) for p in dd + df
490
499
  ]
@@ -689,6 +698,11 @@ def get_sects():
689
698
  \033[36mxban\033[0m can be used to overrule / cancel a user ban event;
690
699
  if the program returns 0 (true/OK) then the ban will NOT happen
691
700
 
701
+ effects can be used to redirect uploads into other
702
+ locations, and to delete or index other files based
703
+ on new uploads, but with certain limitations. See
704
+ bin/hooks/reloc* and docs/devnotes.md#hook-effects
705
+
692
706
  except for \033[36mxm\033[0m, only one hook / one action can run at a time,
693
707
  so it's recommended to use the \033[36mf\033[0m flag unless you really need
694
708
  to wait for the hook to finish before continuing (without \033[36mf\033[0m
@@ -949,8 +963,8 @@ def add_upload(ap):
949
963
 
950
964
  def add_network(ap):
951
965
  ap2 = ap.add_argument_group('network options')
952
- ap2.add_argument("-i", metavar="IP", type=u, default="::", help="ip to bind (comma-sep.), default: all IPv4 and IPv6")
953
- ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to bind (comma/range)")
966
+ ap2.add_argument("-i", metavar="IP", type=u, default="::", help="ip to bind (comma-sep.) and/or [\033[32munix:/tmp/a.sock\033[0m], default: all IPv4 and IPv6")
967
+ ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to bind (comma/range); ignored for unix-sockets")
954
968
  ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)")
955
969
  ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=1, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m2\033[0m]=outermost-proxy, [\033[32m3\033[0m]=second-proxy, [\033[32m-1\033[0m]=closest-proxy")
956
970
  ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from")
@@ -1117,6 +1131,7 @@ def add_hooks(ap):
1117
1131
  ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file delete")
1118
1132
  ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m on message")
1119
1133
  ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)")
1134
+ ap2.add_argument("--hook-v", action="store_true", help="verbose hooks")
1120
1135
 
1121
1136
 
1122
1137
  def add_stats(ap):
@@ -1345,9 +1360,10 @@ def add_ui(ap, retry):
1345
1360
  ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
1346
1361
  ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
1347
1362
  ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
1348
- ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include")
1349
- ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include")
1350
- ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages; can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)")
1363
+ ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html")
1364
+ ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html")
1365
+ ap2.add_argument("--js-other", metavar="L", type=u, default="", help="URL to additional JS to include in all other pages")
1366
+ ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)")
1351
1367
  ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI, or add ?v to URL for override)")
1352
1368
  ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
1353
1369
  ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")
@@ -1366,12 +1382,14 @@ def add_debug(ap):
1366
1382
  ap2 = ap.add_argument_group('debug options')
1367
1383
  ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
1368
1384
  ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
1385
+ ap2.add_argument("--deps", action="store_true", help="list information about detected optional dependencies")
1369
1386
  if hasattr(select, "poll"):
1370
1387
  ap2.add_argument("--no-poll", action="store_true", help="kernel-bug workaround: disable poll; use select instead (limits max num clients to ~700)")
1371
1388
  ap2.add_argument("--no-sendfile", action="store_true", help="kernel-bug workaround: disable sendfile; do a safe and slow read-send-loop instead")
1372
1389
  ap2.add_argument("--no-scandir", action="store_true", help="kernel-bug workaround: disable scandir; do a listdir + stat on each file instead")
1373
1390
  ap2.add_argument("--no-fastboot", action="store_true", help="wait for initial filesystem indexing before accepting client requests")
1374
1391
  ap2.add_argument("--no-htp", action="store_true", help="disable httpserver threadpool, create threads as-needed instead")
1392
+ ap2.add_argument("--rm-sck", action="store_true", help="when listening on unix-sockets, do a basic delete+bind instead of the default atomic bind")
1375
1393
  ap2.add_argument("--srch-dbg", action="store_true", help="explain search processing, and do some extra expensive sanity checks")
1376
1394
  ap2.add_argument("--rclone-mdns", action="store_true", help="use mdns-domain instead of server-ip on /?hc")
1377
1395
  ap2.add_argument("--stackmon", metavar="P,S", type=u, default="", help="write stacktrace to \033[33mP\033[0math every \033[33mS\033[0m second, for example --stackmon=\033[32m./st/%%Y-%%m/%%d/%%H%%M.xz,60")
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 13, 6)
3
+ VERSION = (1, 13, 7)
4
4
  CODENAME = "race the beam"
5
- BUILD_DT = (2024, 7, 29)
5
+ BUILD_DT = (2024, 8, 12)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
@@ -12,7 +12,7 @@ import threading
12
12
  import time
13
13
  from datetime import datetime
14
14
 
15
- from .__init__ import ANYWIN, TYPE_CHECKING, WINDOWS, E
15
+ from .__init__ import ANYWIN, PY2, TYPE_CHECKING, WINDOWS, E
16
16
  from .bos import bos
17
17
  from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
18
18
  from .pwhash import PWHash
@@ -49,6 +49,9 @@ if TYPE_CHECKING:
49
49
  # Vflags: TypeAlias = dict[str, Any]
50
50
  # Mflags: TypeAlias = dict[str, Vflags]
51
51
 
52
+ if PY2:
53
+ range = xrange # type: ignore
54
+
52
55
 
53
56
  LEELOO_DALLAS = "leeloo_dallas"
54
57
 
@@ -434,7 +437,7 @@ class VFS(object):
434
437
 
435
438
  def _find(self, vpath ) :
436
439
  """return [vfs,remainder]"""
437
- if vpath == "":
440
+ if not vpath:
438
441
  return self, ""
439
442
 
440
443
  if "/" in vpath:
@@ -444,7 +447,7 @@ class VFS(object):
444
447
  rem = ""
445
448
 
446
449
  if name in self.nodes:
447
- return self.nodes[name]._find(undot(rem))
450
+ return self.nodes[name]._find(rem)
448
451
 
449
452
  return self, vpath
450
453
 
@@ -511,8 +514,8 @@ class VFS(object):
511
514
  t = "{} has no {} in [{}] => [{}] => [{}]"
512
515
  self.log("vfs", t.format(uname, msg, vpath, cvpath, ap), 6)
513
516
 
514
- t = 'you don\'t have %s-access in "/%s"'
515
- raise Pebkac(err, t % (msg, cvpath))
517
+ t = 'you don\'t have %s-access in "/%s" or below "/%s"'
518
+ raise Pebkac(err, t % (msg, cvpath, vn.vpath))
516
519
 
517
520
  return vn, rem
518
521
 
@@ -1888,7 +1891,7 @@ class AuthSrv(object):
1888
1891
  self.log(t.format(vol.vpath), 1)
1889
1892
  del vol.flags["lifetime"]
1890
1893
 
1891
- needs_e2d = [x for x in hooks if x != "xm"]
1894
+ needs_e2d = [x for x in hooks if x in ("xau", "xiu")]
1892
1895
  drop = [x for x in needs_e2d if vol.flags.get(x)]
1893
1896
  if drop:
1894
1897
  t = 'removing [{}] from volume "/{}" because e2d is disabled'
@@ -9,7 +9,7 @@ import time
9
9
  from .__init__ import ANYWIN
10
10
  from .util import Netdev, runcmd, wrename, wunlink
11
11
 
12
- HAVE_CFSSL = True
12
+ HAVE_CFSSL = not os.environ.get("PRTY_NO_CFSSL")
13
13
 
14
14
  if ANYWIN:
15
15
  VF = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
@@ -9,7 +9,7 @@ import time
9
9
  from .__init__ import ANYWIN, MACOS
10
10
  from .authsrv import AXS, VFS
11
11
  from .bos import bos
12
- from .util import chkcmd, min_ex
12
+ from .util import chkcmd, min_ex, undot
13
13
 
14
14
  class Fstab(object):
15
15
  def __init__(self, log , args ):
@@ -46,7 +46,7 @@ class Fstab(object):
46
46
  self.log(msg.format(path, fs, min_ex()), 3)
47
47
  return fs
48
48
 
49
- path = path.lstrip("/")
49
+ path = undot(path)
50
50
  try:
51
51
  return self.cache[path]
52
52
  except:
@@ -118,7 +118,7 @@ class Fstab(object):
118
118
  if ANYWIN:
119
119
  path = self._winpath(path)
120
120
 
121
- path = path.lstrip("/")
121
+ path = undot(path)
122
122
  ptn = re.compile(r"^[^\\/]*")
123
123
  vn, rem = self.tab._find(path)
124
124
  if not self.trusted:
@@ -37,6 +37,10 @@ from .util import (
37
37
  if TYPE_CHECKING:
38
38
  from .svchub import SvcHub
39
39
 
40
+ if PY2:
41
+ range = xrange # type: ignore
42
+
43
+
40
44
  class FSE(FilesystemError):
41
45
  def __init__(self, msg , severity = 0) :
42
46
  super(FilesystemError, self).__init__(msg)
@@ -345,7 +349,7 @@ class FtpFs(AbstractedFS):
345
349
  svp = join(self.cwd, src).lstrip("/")
346
350
  dvp = join(self.cwd, dst).lstrip("/")
347
351
  try:
348
- self.hub.up2k.handle_mv(self.uname, svp, dvp)
352
+ self.hub.up2k.handle_mv(self.uname, self.h.cli_ip, svp, dvp)
349
353
  except Exception as ex:
350
354
  raise FSE(str(ex))
351
355
 
@@ -463,6 +467,9 @@ class FtpHandler(FTPHandler):
463
467
  xbu = vfs.flags.get("xbu")
464
468
  if xbu and not runhook(
465
469
  None,
470
+ None,
471
+ self.hub.up2k,
472
+ "xbu.ftpd",
466
473
  xbu,
467
474
  ap,
468
475
  vp,
@@ -472,7 +479,7 @@ class FtpHandler(FTPHandler):
472
479
  0,
473
480
  0,
474
481
  self.cli_ip,
475
- 0,
482
+ time.time(),
476
483
  "",
477
484
  ):
478
485
  raise FSE("Upload blocked by xbu server config")
@@ -575,9 +582,15 @@ class Ftpd(object):
575
582
  if "::" in ips:
576
583
  ips.append("0.0.0.0")
577
584
 
585
+ ips = [x for x in ips if "unix:" not in x]
586
+
578
587
  if self.args.ftp4:
579
588
  ips = [x for x in ips if ":" not in x]
580
589
 
590
+ if not ips:
591
+ lgr.fatal("cannot start ftp-server; no compatible IPs in -i")
592
+ return
593
+
581
594
  ips = list(ODict.fromkeys(ips)) # dedup
582
595
 
583
596
  ioloop = IOLoop()