copyparty 1.16.17__tar.gz → 1.16.18__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.16.17 → copyparty-1.16.18}/PKG-INFO +4 -3
- {copyparty-1.16.17 → copyparty-1.16.18}/README.md +1 -1
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/__main__.py +6 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/__version__.py +2 -2
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/cfg.py +2 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/ftpd.py +11 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/httpcli.py +19 -1
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/mtag.py +1 -2
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/svchub.py +3 -2
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/szip.py +1 -2
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/tcpsrv.py +18 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/tftpd.py +29 -8
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/up2k.py +5 -3
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/util.py +30 -3
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/PKG-INFO +4 -3
- {copyparty-1.16.17 → copyparty-1.16.18}/LICENSE +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/authsrv.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/bos/bos.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/bos/path.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/broker_mp.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/broker_thr.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/broker_util.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/cert.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/dxml.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/fsutil.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/httpconn.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/httpsrv.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/ico.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/mdns.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/metrics.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/multicast.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/pwhash.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/res/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/smbd.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/ssdp.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/star.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/sutil.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/th_cli.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/th_srv.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/u2idx.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/browser.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/browser.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/browser2.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/cf.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/md.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/mde.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/msg.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/rups.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/rups.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/rups.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/shares.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/shares.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/splash.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/svcs.html +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/pyproject.toml +0 -0
- {copyparty-1.16.17 → copyparty-1.16.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.18
|
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
|
@@ -54,6 +54,7 @@ Provides-Extra: pwhash
|
|
54
54
|
Requires-Dist: argon2-cffi; extra == "pwhash"
|
55
55
|
Provides-Extra: zeromq
|
56
56
|
Requires-Dist: pyzmq; extra == "zeromq"
|
57
|
+
Dynamic: license-file
|
57
58
|
|
58
59
|
<img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
|
59
60
|
|
@@ -157,7 +158,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
157
158
|
* [custom mimetypes](#custom-mimetypes) - change the association of a file extension
|
158
159
|
* [GDPR compliance](#GDPR-compliance) - imagine using copyparty professionally...
|
159
160
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
160
|
-
* [feature beefybits](#feature-beefybits) - force-enable
|
161
|
+
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
161
162
|
* [packages](#packages) - the party might be closer than you think
|
162
163
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
163
164
|
* [fedora package](#fedora-package) - does not exist yet
|
@@ -100,7 +100,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
100
100
|
* [custom mimetypes](#custom-mimetypes) - change the association of a file extension
|
101
101
|
* [GDPR compliance](#GDPR-compliance) - imagine using copyparty professionally...
|
102
102
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
103
|
-
* [feature beefybits](#feature-beefybits) - force-enable
|
103
|
+
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
104
104
|
* [packages](#packages) - the party might be closer than you think
|
105
105
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
106
106
|
* [fedora package](#fedora-package) - does not exist yet
|
@@ -40,6 +40,7 @@ from .cfg import flagcats, onedash
|
|
40
40
|
from .svchub import SvcHub
|
41
41
|
from .util import (
|
42
42
|
APPLESAN_TXT,
|
43
|
+
BAD_BOTS,
|
43
44
|
DEF_EXP,
|
44
45
|
DEF_MTE,
|
45
46
|
DEF_MTH,
|
@@ -1021,6 +1022,8 @@ def add_network(ap):
|
|
1021
1022
|
ap2.add_argument("--reuseaddr", action="store_true", help="set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances")
|
1022
1023
|
else:
|
1023
1024
|
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)")
|
1025
|
+
ap2.add_argument("--wr-h-eps", metavar="PATH", type=u, default="", help="write list of listening-on ip:port to textfile at \033[33mPATH\033[0m when http-servers have started")
|
1026
|
+
ap2.add_argument("--wr-h-aon", metavar="PATH", type=u, default="", help="write list of accessible-on ip:port to textfile at \033[33mPATH\033[0m when http-servers have started")
|
1024
1027
|
ap2.add_argument("--s-thead", metavar="SEC", type=int, default=120, help="socket timeout (read request header)")
|
1025
1028
|
ap2.add_argument("--s-tbody", metavar="SEC", type=float, default=128.0, 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")
|
1026
1029
|
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)")
|
@@ -1214,6 +1217,7 @@ def add_yolo(ap):
|
|
1214
1217
|
ap2 = ap.add_argument_group('yolo options')
|
1215
1218
|
ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests")
|
1216
1219
|
ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET")
|
1220
|
+
ap2.add_argument("--wo-up-readme", action="store_true", help="allow users with write-only access to upload logues and readmes without adding the _wo_ filename prefix (volflag=wo_up_readme)")
|
1217
1221
|
|
1218
1222
|
|
1219
1223
|
def add_optouts(ap):
|
@@ -1233,6 +1237,7 @@ def add_optouts(ap):
|
|
1233
1237
|
ap2.add_argument("--zipmaxt", metavar="TXT", type=u, default="", help="custom errormessage when download size exceeds max (volflag=zipmaxt)")
|
1234
1238
|
ap2.add_argument("--zipmaxu", action="store_true", help="authenticated users bypass the zip size limit (volflag=zipmaxu)")
|
1235
1239
|
ap2.add_argument("--zip-who", metavar="LVL", type=int, default=3, help="who can download as zip/tar? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=authenticated-with-read-access, [\033[32m3\033[0m]=everyone-with-read-access (volflag=zip_who)\n\033[1;31mWARNING:\033[0m if a nested volume has a more restrictive value than a parent volume, then this will be \033[33mignored\033[0m if the download is initiated from the parent, more lenient volume")
|
1240
|
+
ap2.add_argument("--ua-nozip", metavar="PTN", type=u, default=BAD_BOTS, help="regex of user-agents to reject from download-as-zip/tar; disable with [\033[32mno\033[0m] or blank")
|
1236
1241
|
ap2.add_argument("--no-zip", action="store_true", help="disable download as zip/tar; same as \033[33m--zip-who=0\033[0m")
|
1237
1242
|
ap2.add_argument("--no-tarcmp", action="store_true", help="disable download as compressed tar (?tar=gz, ?tar=bz2, ?tar=xz, ?tar=gz:9, ...)")
|
1238
1243
|
ap2.add_argument("--no-lifetime", action="store_true", help="do not allow clients (or server config) to schedule an upload to be deleted after a given time")
|
@@ -1423,6 +1428,7 @@ def add_txt(ap):
|
|
1423
1428
|
ap2.add_argument("--exp", action="store_true", help="enable textfile expansion -- replace {{self.ip}} and such; see \033[33m--help-exp\033[0m (volflag=exp)")
|
1424
1429
|
ap2.add_argument("--exp-md", metavar="V,V,V", type=u, default=DEF_EXP, help="comma/space-separated list of placeholders to expand in markdown files; add/remove stuff on the default list with +hdr_foo or /vf.scan (volflag=exp_md)")
|
1425
1430
|
ap2.add_argument("--exp-lg", metavar="V,V,V", type=u, default=DEF_EXP, help="comma/space-separated list of placeholders to expand in prologue/epilogue files (volflag=exp_lg)")
|
1431
|
+
ap2.add_argument("--ua-nodoc", metavar="PTN", type=u, default=BAD_BOTS, help="regex of user-agents to reject from viewing documents through ?doc=[...]; disable with [\033[32mno\033[0m] or blank")
|
1426
1432
|
|
1427
1433
|
|
1428
1434
|
def add_og(ap):
|
@@ -52,6 +52,7 @@ def vf_bmap() :
|
|
52
52
|
"og_s_title",
|
53
53
|
"rand",
|
54
54
|
"rss",
|
55
|
+
"wo_up_readme",
|
55
56
|
"xdev",
|
56
57
|
"xlink",
|
57
58
|
"xvol",
|
@@ -173,6 +174,7 @@ flagcats = {
|
|
173
174
|
"vmaxb=1g": "total volume size max 1 GiB (suffixes: b, k, m, g, t)",
|
174
175
|
"vmaxn=4k": "max 4096 files in volume (suffixes: b, k, m, g, t)",
|
175
176
|
"medialinks": "return medialinks for non-up2k uploads (not hotlinks)",
|
177
|
+
"wo_up_readme": "write-only users can upload logues without getting renamed",
|
176
178
|
"rand": "force randomized filenames, 9 chars long by default",
|
177
179
|
"nrand=N": "randomized filenames are N chars long",
|
178
180
|
"u2ow=N": "overwrite existing files? 0=no 1=if-older 2=always",
|
@@ -19,6 +19,7 @@ from .__init__ import PY2, TYPE_CHECKING
|
|
19
19
|
from .authsrv import VFS
|
20
20
|
from .bos import bos
|
21
21
|
from .util import (
|
22
|
+
FN_EMB,
|
22
23
|
VF_CAREFUL,
|
23
24
|
Daemon,
|
24
25
|
ODict,
|
@@ -166,6 +167,16 @@ class FtpFs(AbstractedFS):
|
|
166
167
|
fn = sanitize_fn(fn or "", "")
|
167
168
|
vpath = vjoin(rd, fn)
|
168
169
|
vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
|
170
|
+
if (
|
171
|
+
w
|
172
|
+
and fn.lower() in FN_EMB
|
173
|
+
and self.h.uname not in vfs.axs.uread
|
174
|
+
and "wo_up_readme" not in vfs.flags
|
175
|
+
):
|
176
|
+
fn = "_wo_" + fn
|
177
|
+
vpath = vjoin(rd, fn)
|
178
|
+
vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
|
179
|
+
|
169
180
|
if not vfs.realpath:
|
170
181
|
t = "No filesystem mounted at [{}]"
|
171
182
|
raise FSE(t.format(vpath))
|
@@ -4,7 +4,6 @@ from __future__ import print_function, unicode_literals
|
|
4
4
|
import argparse # typechk
|
5
5
|
import copy
|
6
6
|
import errno
|
7
|
-
import gzip
|
8
7
|
import hashlib
|
9
8
|
import itertools
|
10
9
|
import json
|
@@ -46,6 +45,7 @@ from .util import (
|
|
46
45
|
APPLESAN_RE,
|
47
46
|
BITNESS,
|
48
47
|
DAV_ALLPROPS,
|
48
|
+
FN_EMB,
|
49
49
|
HAVE_SQLITE3,
|
50
50
|
HTTPCODE,
|
51
51
|
META_NOBOTS,
|
@@ -69,6 +69,7 @@ from .util import (
|
|
69
69
|
get_df,
|
70
70
|
get_spd,
|
71
71
|
guess_mime,
|
72
|
+
gzip,
|
72
73
|
gzip_file_orig_sz,
|
73
74
|
gzip_orig_sz,
|
74
75
|
has_resource,
|
@@ -2539,6 +2540,16 @@ class HttpCli(object):
|
|
2539
2540
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2540
2541
|
dbv, vrem = vfs.get_dbv(rem)
|
2541
2542
|
|
2543
|
+
name = sanitize_fn(name, "")
|
2544
|
+
if (
|
2545
|
+
not self.can_read
|
2546
|
+
and self.can_write
|
2547
|
+
and name.lower() in FN_EMB
|
2548
|
+
and "wo_up_readme" not in dbv.flags
|
2549
|
+
):
|
2550
|
+
name = "_wo_" + name
|
2551
|
+
|
2552
|
+
body["name"] = name
|
2542
2553
|
body["vtop"] = dbv.vpath
|
2543
2554
|
body["ptop"] = dbv.realpath
|
2544
2555
|
body["prel"] = vrem
|
@@ -3778,6 +3789,9 @@ class HttpCli(object):
|
|
3778
3789
|
return "download-as-zip/tar is admin-only on this server"
|
3779
3790
|
elif lvl <= 2 and self.uname in ("", "*"):
|
3780
3791
|
return "you must be authenticated to download-as-zip/tar on this server"
|
3792
|
+
elif self.args.ua_nozip and self.args.ua_nozip.search(self.ua):
|
3793
|
+
t = "this URL contains no valuable information for bots/crawlers"
|
3794
|
+
raise Pebkac(403, t)
|
3781
3795
|
return ""
|
3782
3796
|
|
3783
3797
|
def tx_res(self, req_path ) :
|
@@ -6257,6 +6271,10 @@ class HttpCli(object):
|
|
6257
6271
|
|
6258
6272
|
doc = self.uparam.get("doc") if self.can_read else None
|
6259
6273
|
if doc:
|
6274
|
+
zp = self.args.ua_nodoc
|
6275
|
+
if zp and zp.search(self.ua):
|
6276
|
+
t = "this URL contains no valuable information for bots/crawlers"
|
6277
|
+
raise Pebkac(403, t)
|
6260
6278
|
j2a["docname"] = doc
|
6261
6279
|
doctxt = None
|
6262
6280
|
dfn = lnames.get(doc.lower())
|
@@ -18,6 +18,7 @@ from .util import (
|
|
18
18
|
REKOBO_LKEY,
|
19
19
|
VF_CAREFUL,
|
20
20
|
fsenc,
|
21
|
+
gzip,
|
21
22
|
min_ex,
|
22
23
|
pybin,
|
23
24
|
retchk,
|
@@ -132,8 +133,6 @@ def au_unpk(
|
|
132
133
|
fd, ret = tempfile.mkstemp("." + au)
|
133
134
|
|
134
135
|
if pk == "gz":
|
135
|
-
import gzip
|
136
|
-
|
137
136
|
fi = gzip.GzipFile(abspath, mode="rb")
|
138
137
|
|
139
138
|
elif pk == "xz":
|
@@ -3,7 +3,6 @@ from __future__ import print_function, unicode_literals
|
|
3
3
|
|
4
4
|
import argparse
|
5
5
|
import errno
|
6
|
-
import gzip
|
7
6
|
import logging
|
8
7
|
import os
|
9
8
|
import re
|
@@ -57,6 +56,7 @@ from .util import (
|
|
57
56
|
ansi_re,
|
58
57
|
build_netmap,
|
59
58
|
expat_ver,
|
59
|
+
gzip,
|
60
60
|
load_ipu,
|
61
61
|
min_ex,
|
62
62
|
mp,
|
@@ -759,7 +759,8 @@ class SvcHub(object):
|
|
759
759
|
vs = os.path.expandvars(os.path.expanduser(vs))
|
760
760
|
setattr(al, k, vs)
|
761
761
|
|
762
|
-
|
762
|
+
zs = "dav_ua1 sus_urls nonsus_urls ua_nodoc ua_nozip"
|
763
|
+
for k in zs.split(" "):
|
763
764
|
vs = getattr(al, k)
|
764
765
|
if not vs or vs == "no":
|
765
766
|
setattr(al, k, None)
|
@@ -4,12 +4,11 @@ from __future__ import print_function, unicode_literals
|
|
4
4
|
import calendar
|
5
5
|
import stat
|
6
6
|
import time
|
7
|
-
import zlib
|
8
7
|
|
9
8
|
from .authsrv import AuthSrv
|
10
9
|
from .bos import bos
|
11
10
|
from .sutil import StreamArc, errdesc
|
12
|
-
from .util import min_ex, sanitize_fn, spack, sunpack, yieldfile
|
11
|
+
from .util import min_ex, sanitize_fn, spack, sunpack, yieldfile, zlib
|
13
12
|
|
14
13
|
def dostime2unix(buf ) :
|
15
14
|
t, d = sunpack(b"<HH", buf)
|
@@ -148,9 +148,15 @@ class TcpSrv(object):
|
|
148
148
|
if just_ll or self.args.ll:
|
149
149
|
ll_ok.add(ip.split("/")[0])
|
150
150
|
|
151
|
+
listening_on = []
|
152
|
+
for ip, ports in sorted(ok.items()):
|
153
|
+
for port in sorted(ports):
|
154
|
+
listening_on.append("%s %s" % (ip, port))
|
155
|
+
|
151
156
|
qr1 = {}
|
152
157
|
qr2 = {}
|
153
158
|
msgs = []
|
159
|
+
accessible_on = []
|
154
160
|
title_tab = {}
|
155
161
|
title_vars = [x[1:] for x in self.args.wintitle.split(" ") if x.startswith("$")]
|
156
162
|
t = "available @ {}://{}:{}/ (\033[33m{}\033[0m)"
|
@@ -166,6 +172,10 @@ class TcpSrv(object):
|
|
166
172
|
):
|
167
173
|
continue
|
168
174
|
|
175
|
+
zs = "%s %s" % (ip, port)
|
176
|
+
if zs not in accessible_on:
|
177
|
+
accessible_on.append(zs)
|
178
|
+
|
169
179
|
proto = " http"
|
170
180
|
if self.args.http_only:
|
171
181
|
pass
|
@@ -216,6 +226,14 @@ class TcpSrv(object):
|
|
216
226
|
else:
|
217
227
|
print("\n", end="")
|
218
228
|
|
229
|
+
for fn, ls in (
|
230
|
+
(self.args.wr_h_eps, listening_on),
|
231
|
+
(self.args.wr_h_aon, accessible_on),
|
232
|
+
):
|
233
|
+
if fn:
|
234
|
+
with open(fn, "wb") as f:
|
235
|
+
f.write(("\n".join(ls)).encode("utf-8"))
|
236
|
+
|
219
237
|
if self.args.qr or self.args.qrs:
|
220
238
|
self.qr = self._qr(qr1, qr2)
|
221
239
|
|
@@ -36,7 +36,19 @@ from partftpy.TftpShared import TftpException
|
|
36
36
|
from .__init__ import EXE, PY2, TYPE_CHECKING
|
37
37
|
from .authsrv import VFS
|
38
38
|
from .bos import bos
|
39
|
-
from .util import
|
39
|
+
from .util import (
|
40
|
+
FN_EMB,
|
41
|
+
UTC,
|
42
|
+
BytesIO,
|
43
|
+
Daemon,
|
44
|
+
ODict,
|
45
|
+
exclude_dotfiles,
|
46
|
+
min_ex,
|
47
|
+
runhook,
|
48
|
+
undot,
|
49
|
+
vjoin,
|
50
|
+
vsplit,
|
51
|
+
)
|
40
52
|
|
41
53
|
if TYPE_CHECKING:
|
42
54
|
from .svchub import SvcHub
|
@@ -241,16 +253,25 @@ class Tftpd(object):
|
|
241
253
|
for srv in srvs:
|
242
254
|
srv.stop()
|
243
255
|
|
244
|
-
def _v2a(
|
256
|
+
def _v2a(
|
257
|
+
self, caller , vpath , perms , *a
|
258
|
+
) :
|
245
259
|
vpath = vpath.replace("\\", "/").lstrip("/")
|
246
260
|
if not perms:
|
247
261
|
perms = [True, True]
|
248
262
|
|
249
263
|
debug('%s("%s", %s) %s\033[K\033[0m', caller, vpath, str(a), perms)
|
250
264
|
vfs, rem = self.asrv.vfs.get(vpath, "*", *perms)
|
265
|
+
if perms[1] and "*" not in vfs.axs.uread and "wo_up_readme" not in vfs.flags:
|
266
|
+
zs, fn = vsplit(vpath)
|
267
|
+
if fn.lower() in FN_EMB:
|
268
|
+
vpath = vjoin(zs, "_wo_" + fn)
|
269
|
+
vfs, rem = self.asrv.vfs.get(vpath, "*", *perms)
|
270
|
+
|
251
271
|
if not vfs.realpath:
|
252
272
|
raise Exception("unmapped vfs")
|
253
|
-
|
273
|
+
|
274
|
+
return vfs, vpath, vfs.canonical(rem)
|
254
275
|
|
255
276
|
def _ls(self, vpath , raddress , rport , force=False) :
|
256
277
|
# generate file listing if vpath is dir.txt and return as file object
|
@@ -328,7 +349,7 @@ class Tftpd(object):
|
|
328
349
|
else:
|
329
350
|
raise Exception("bad mode %s" % (mode,))
|
330
351
|
|
331
|
-
vfs, ap = self._v2a("open", vpath, [rd, wr])
|
352
|
+
vfs, vpath, ap = self._v2a("open", vpath, [rd, wr])
|
332
353
|
if wr:
|
333
354
|
if "*" not in vfs.axs.uwrite:
|
334
355
|
yeet("blocked write; folder not world-writable: /%s" % (vpath,))
|
@@ -365,7 +386,7 @@ class Tftpd(object):
|
|
365
386
|
return open(ap, mode, *a, **ka)
|
366
387
|
|
367
388
|
def _mkdir(self, vpath , *a) :
|
368
|
-
vfs, ap = self._v2a("mkdir", vpath, [])
|
389
|
+
vfs, _, ap = self._v2a("mkdir", vpath, [False, True])
|
369
390
|
if "*" not in vfs.axs.uwrite:
|
370
391
|
yeet("blocked mkdir; folder not world-writable: /%s" % (vpath,))
|
371
392
|
|
@@ -373,7 +394,7 @@ class Tftpd(object):
|
|
373
394
|
|
374
395
|
def _unlink(self, vpath ) :
|
375
396
|
# return bos.unlink(self._v2a("stat", vpath, *a)[1])
|
376
|
-
vfs, ap = self._v2a("delete", vpath, [True, False, False, True])
|
397
|
+
vfs, _, ap = self._v2a("delete", vpath, [True, False, False, True])
|
377
398
|
|
378
399
|
try:
|
379
400
|
inf = bos.stat(ap)
|
@@ -397,7 +418,7 @@ class Tftpd(object):
|
|
397
418
|
|
398
419
|
def _p_exists(self, vpath ) :
|
399
420
|
try:
|
400
|
-
ap = self._v2a("p.exists", vpath, [False, False])[
|
421
|
+
ap = self._v2a("p.exists", vpath, [False, False])[2]
|
401
422
|
bos.stat(ap)
|
402
423
|
return True
|
403
424
|
except:
|
@@ -405,7 +426,7 @@ class Tftpd(object):
|
|
405
426
|
|
406
427
|
def _p_isdir(self, vpath ) :
|
407
428
|
try:
|
408
|
-
st = bos.stat(self._v2a("p.isdir", vpath, [False, False])[
|
429
|
+
st = bos.stat(self._v2a("p.isdir", vpath, [False, False])[2])
|
409
430
|
ret = stat.S_ISDIR(st.st_mode)
|
410
431
|
return ret
|
411
432
|
except:
|
@@ -2,7 +2,6 @@
|
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
4
|
import errno
|
5
|
-
import gzip
|
6
5
|
import hashlib
|
7
6
|
import json
|
8
7
|
import math
|
@@ -42,6 +41,7 @@ from .util import (
|
|
42
41
|
fsenc,
|
43
42
|
gen_filekey,
|
44
43
|
gen_filekey_dbg,
|
44
|
+
gzip,
|
45
45
|
hidedir,
|
46
46
|
humansize,
|
47
47
|
min_ex,
|
@@ -2903,7 +2903,6 @@ class Up2k(object):
|
|
2903
2903
|
if ptop not in self.registry:
|
2904
2904
|
raise Pebkac(410, "location unavailable")
|
2905
2905
|
|
2906
|
-
cj["name"] = sanitize_fn(cj["name"], "")
|
2907
2906
|
cj["poke"] = now = self.db_act = self.vol_act[ptop] = time.time()
|
2908
2907
|
wark = dwark = self._get_wark(cj)
|
2909
2908
|
job = None
|
@@ -3220,6 +3219,7 @@ class Up2k(object):
|
|
3220
3219
|
job["ptop"] = vfs.realpath
|
3221
3220
|
job["vtop"] = vfs.vpath
|
3222
3221
|
job["prel"] = rem
|
3222
|
+
job["name"] = sanitize_fn(job["name"], "")
|
3223
3223
|
if zvfs.vpath != vfs.vpath:
|
3224
3224
|
# print(json.dumps(job, sort_keys=True, indent=4))
|
3225
3225
|
job["hash"] = cj["hash"]
|
@@ -3692,8 +3692,9 @@ class Up2k(object):
|
|
3692
3692
|
if self.idx_wark(vflags, *z2):
|
3693
3693
|
del self.registry[ptop][wark]
|
3694
3694
|
else:
|
3695
|
-
for k in "host tnam busy sprs poke
|
3695
|
+
for k in "host tnam busy sprs poke".split():
|
3696
3696
|
del job[k]
|
3697
|
+
job.pop("t0c", None)
|
3697
3698
|
job["t0"] = int(job["t0"])
|
3698
3699
|
job["hash"] = []
|
3699
3700
|
job["done"] = 1
|
@@ -4972,6 +4973,7 @@ class Up2k(object):
|
|
4972
4973
|
job["ptop"] = vfs.realpath
|
4973
4974
|
job["vtop"] = vfs.vpath
|
4974
4975
|
job["prel"] = rem
|
4976
|
+
job["name"] = sanitize_fn(job["name"], "")
|
4975
4977
|
if zvfs.vpath != vfs.vpath:
|
4976
4978
|
self.log("xbu reloc2:%d..." % (depth,), 6)
|
4977
4979
|
return self._handle_json(job, depth + 1)
|
@@ -31,6 +31,17 @@ from collections import Counter
|
|
31
31
|
from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network
|
32
32
|
from queue import Queue
|
33
33
|
|
34
|
+
try:
|
35
|
+
from zlib_ng import gzip_ng as gzip
|
36
|
+
from zlib_ng import zlib_ng as zlib
|
37
|
+
|
38
|
+
sys.modules["gzip"] = gzip
|
39
|
+
# sys.modules["zlib"] = zlib
|
40
|
+
# `- somehow makes tarfile 3% slower with default malloc, and barely faster with mimalloc
|
41
|
+
except:
|
42
|
+
import gzip
|
43
|
+
import zlib
|
44
|
+
|
34
45
|
from .__init__ import (
|
35
46
|
ANYWIN,
|
36
47
|
EXE,
|
@@ -213,6 +224,9 @@ SYMTIME = PY36 and os.utime in os.supports_follow_symlinks
|
|
213
224
|
|
214
225
|
META_NOBOTS = '<meta name="robots" content="noindex, nofollow">\n'
|
215
226
|
|
227
|
+
# smart enough to understand javascript while also ignoring rel="nofollow"
|
228
|
+
BAD_BOTS = r"Barkrowler|bingbot|BLEXBot|Googlebot|GPTBot|PetalBot|SeekportBot|SemrushBot|YandexBot"
|
229
|
+
|
216
230
|
FFMPEG_URL = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
|
217
231
|
|
218
232
|
URL_PRJ = "https://github.com/9001/copyparty"
|
@@ -427,6 +441,8 @@ UNHUMANIZE_UNITS = {
|
|
427
441
|
|
428
442
|
VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
|
429
443
|
|
444
|
+
FN_EMB = set([".prologue.html", ".epilogue.html", "readme.md", "preadme.md"])
|
445
|
+
|
430
446
|
|
431
447
|
def read_ram() :
|
432
448
|
a = b = 0
|
@@ -1369,8 +1385,6 @@ def stackmon(fp , ival , suffix ) :
|
|
1369
1385
|
buf = st.encode("utf-8", "replace")
|
1370
1386
|
|
1371
1387
|
if fp.endswith(".gz"):
|
1372
|
-
import gzip
|
1373
|
-
|
1374
1388
|
# 2459b 2304b 2241b 2202b 2194b 2191b lv3..8
|
1375
1389
|
# 0.06s 0.08s 0.11s 0.13s 0.16s 0.19s
|
1376
1390
|
buf = gzip.compress(buf, compresslevel=6)
|
@@ -3958,9 +3972,22 @@ class WrongPostKey(Pebkac):
|
|
3958
3972
|
self.datagen = datagen
|
3959
3973
|
|
3960
3974
|
|
3961
|
-
_ = (
|
3975
|
+
_ = (
|
3976
|
+
gzip,
|
3977
|
+
mp,
|
3978
|
+
zlib,
|
3979
|
+
BytesIO,
|
3980
|
+
quote,
|
3981
|
+
unquote,
|
3982
|
+
SQLITE_VER,
|
3983
|
+
JINJA_VER,
|
3984
|
+
PYFTPD_VER,
|
3985
|
+
PARTFTPY_VER,
|
3986
|
+
)
|
3962
3987
|
__all__ = [
|
3988
|
+
"gzip",
|
3963
3989
|
"mp",
|
3990
|
+
"zlib",
|
3964
3991
|
"BytesIO",
|
3965
3992
|
"quote",
|
3966
3993
|
"unquote",
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.18
|
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
|
@@ -54,6 +54,7 @@ Provides-Extra: pwhash
|
|
54
54
|
Requires-Dist: argon2-cffi; extra == "pwhash"
|
55
55
|
Provides-Extra: zeromq
|
56
56
|
Requires-Dist: pyzmq; extra == "zeromq"
|
57
|
+
Dynamic: license-file
|
57
58
|
|
58
59
|
<img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
|
59
60
|
|
@@ -157,7 +158,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
157
158
|
* [custom mimetypes](#custom-mimetypes) - change the association of a file extension
|
158
159
|
* [GDPR compliance](#GDPR-compliance) - imagine using copyparty professionally...
|
159
160
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
160
|
-
* [feature beefybits](#feature-beefybits) - force-enable
|
161
|
+
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
161
162
|
* [packages](#packages) - the party might be closer than you think
|
162
163
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
163
164
|
* [fedora package](#fedora-package) - does not exist yet
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|