copyparty 1.8.0__tar.gz → 1.8.1__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.8.0 → copyparty-1.8.1}/PKG-INFO +23 -1
- {copyparty-1.8.0 → copyparty-1.8.1}/README.md +22 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/__main__.py +53 -1
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/__version__.py +2 -2
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/authsrv.py +3 -3
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/cfg.py +4 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/httpcli.py +50 -5
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/ico.py +14 -3
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/util.py +28 -0
- copyparty-1.8.1/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/PKG-INFO +23 -1
- copyparty-1.8.0/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/LICENSE +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/bos/bos.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/bos/path.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/broker_mp.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/broker_thr.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/broker_util.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/cert.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/dxml.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/fsutil.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/ftpd.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/httpconn.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/httpsrv.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/mdns.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/mtag.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/multicast.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/pwhash.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/res/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/smbd.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/ssdp.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/star.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/sutil.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/svchub.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/szip.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/th_cli.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/th_srv.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/u2idx.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/up2k.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/browser.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/browser.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/browser2.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/cf.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/md.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/mde.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/msg.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/splash.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/svcs.html +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/util.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/pyproject.toml +0 -0
- {copyparty-1.8.0 → copyparty-1.8.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.8.
|
3
|
+
Version: 1.8.1
|
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
|
@@ -109,12 +109,14 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
109
109
|
* [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
|
110
110
|
* [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
|
111
111
|
* [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
|
112
|
+
* [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
|
112
113
|
* [hiding from google](#hiding-from-google) - tell search engines you dont wanna be indexed
|
113
114
|
* [themes](#themes)
|
114
115
|
* [complete examples](#complete-examples)
|
115
116
|
* [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
|
116
117
|
* [packages](#packages) - the party might be closer than you think
|
117
118
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
119
|
+
* [fedora package](#fedora-package) - now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/)
|
118
120
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
119
121
|
* [nixos module](#nixos-module)
|
120
122
|
* [browser support](#browser-support) - TLDR: yes
|
@@ -1169,6 +1171,13 @@ note that this is way more complicated than the new [event hooks](#event-hooks)
|
|
1169
1171
|
note that it will occupy the parsing threads, so fork anything expensive (or set `kn` to have copyparty fork it for you) -- otoh if you want to intentionally queue/singlethread you can combine it with `--mtag-mt 1`
|
1170
1172
|
|
1171
1173
|
|
1174
|
+
## handlers
|
1175
|
+
|
1176
|
+
redefine behavior with plugins ([examples](./bin/handlers/))
|
1177
|
+
|
1178
|
+
replace 404 and 403 errors with something completely different (that's it for now)
|
1179
|
+
|
1180
|
+
|
1172
1181
|
## hiding from google
|
1173
1182
|
|
1174
1183
|
tell search engines you dont wanna be indexed, either using the good old [robots.txt](https://www.robotstxt.org/robotstxt.html) or through copyparty settings:
|
@@ -1271,6 +1280,19 @@ the party might be closer than you think
|
|
1271
1280
|
now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
1272
1281
|
|
1273
1282
|
|
1283
|
+
## fedora package
|
1284
|
+
|
1285
|
+
now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/) , maintained autonomously -- [track record](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/package/python-copyparty/) seems OK
|
1286
|
+
|
1287
|
+
```bash
|
1288
|
+
dnf copr enable @copr/PyPI
|
1289
|
+
dnf install python3-copyparty # just a minimal install, or...
|
1290
|
+
dnf install python3-{copyparty,pillow,argon2-cffi,pyftpdlib,pyOpenSSL} ffmpeg-free # with recommended deps
|
1291
|
+
```
|
1292
|
+
|
1293
|
+
this *may* also work on RHEL but [I'm not paying IBM to verify that](https://www.jeffgeerling.com/blog/2023/dear-red-hat-are-you-dumb)
|
1294
|
+
|
1295
|
+
|
1274
1296
|
## nix package
|
1275
1297
|
|
1276
1298
|
`nix profile install github:9001/copyparty`
|
@@ -66,12 +66,14 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
66
66
|
* [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
|
67
67
|
* [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
|
68
68
|
* [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
|
69
|
+
* [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
|
69
70
|
* [hiding from google](#hiding-from-google) - tell search engines you dont wanna be indexed
|
70
71
|
* [themes](#themes)
|
71
72
|
* [complete examples](#complete-examples)
|
72
73
|
* [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
|
73
74
|
* [packages](#packages) - the party might be closer than you think
|
74
75
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
76
|
+
* [fedora package](#fedora-package) - now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/)
|
75
77
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
76
78
|
* [nixos module](#nixos-module)
|
77
79
|
* [browser support](#browser-support) - TLDR: yes
|
@@ -1126,6 +1128,13 @@ note that this is way more complicated than the new [event hooks](#event-hooks)
|
|
1126
1128
|
note that it will occupy the parsing threads, so fork anything expensive (or set `kn` to have copyparty fork it for you) -- otoh if you want to intentionally queue/singlethread you can combine it with `--mtag-mt 1`
|
1127
1129
|
|
1128
1130
|
|
1131
|
+
## handlers
|
1132
|
+
|
1133
|
+
redefine behavior with plugins ([examples](./bin/handlers/))
|
1134
|
+
|
1135
|
+
replace 404 and 403 errors with something completely different (that's it for now)
|
1136
|
+
|
1137
|
+
|
1129
1138
|
## hiding from google
|
1130
1139
|
|
1131
1140
|
tell search engines you dont wanna be indexed, either using the good old [robots.txt](https://www.robotstxt.org/robotstxt.html) or through copyparty settings:
|
@@ -1228,6 +1237,19 @@ the party might be closer than you think
|
|
1228
1237
|
now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
1229
1238
|
|
1230
1239
|
|
1240
|
+
## fedora package
|
1241
|
+
|
1242
|
+
now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/) , maintained autonomously -- [track record](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/package/python-copyparty/) seems OK
|
1243
|
+
|
1244
|
+
```bash
|
1245
|
+
dnf copr enable @copr/PyPI
|
1246
|
+
dnf install python3-copyparty # just a minimal install, or...
|
1247
|
+
dnf install python3-{copyparty,pillow,argon2-cffi,pyftpdlib,pyOpenSSL} ffmpeg-free # with recommended deps
|
1248
|
+
```
|
1249
|
+
|
1250
|
+
this *may* also work on RHEL but [I'm not paying IBM to verify that](https://www.jeffgeerling.com/blog/2023/dear-red-hat-are-you-dumb)
|
1251
|
+
|
1252
|
+
|
1231
1253
|
## nix package
|
1232
1254
|
|
1233
1255
|
`nix profile install github:9001/copyparty`
|
@@ -522,6 +522,50 @@ def get_sects():
|
|
522
522
|
).rstrip()
|
523
523
|
+ build_flags_desc(),
|
524
524
|
],
|
525
|
+
[
|
526
|
+
"handlers",
|
527
|
+
"use plugins to handle certain events",
|
528
|
+
dedent(
|
529
|
+
"""
|
530
|
+
usually copyparty returns a \033[33m404\033[0m if a file does not exist, and
|
531
|
+
\033[33m403\033[0m if a user tries to access a file they don't have access to
|
532
|
+
|
533
|
+
you can load a plugin which will be invoked right before this
|
534
|
+
happens, and the plugin can choose to override this behavior
|
535
|
+
|
536
|
+
load the plugin using --args or volflags; for example \033[36m
|
537
|
+
--on404 ~/partyhandlers/not404.py
|
538
|
+
-v .::r:c,on404=~/partyhandlers/not404.py
|
539
|
+
\033[0m
|
540
|
+
the file must define the function \033[35mmain(cli,vn,rem)\033[0m:
|
541
|
+
\033[35mcli\033[0m: the copyparty HttpCli instance
|
542
|
+
\033[35mvn\033[0m: the VFS which overlaps with the requested URL
|
543
|
+
\033[35mrem\033[0m: the remainder of the URL below the VFS mountpoint
|
544
|
+
|
545
|
+
`main` must return a string; one of the following:
|
546
|
+
|
547
|
+
> \033[32m"true"\033[0m: the plugin has responded to the request,
|
548
|
+
and the TCP connection should be kept open
|
549
|
+
|
550
|
+
> \033[32m"false"\033[0m: the plugin has responded to the request,
|
551
|
+
and the TCP connection should be terminated
|
552
|
+
|
553
|
+
> \033[32m"retry"\033[0m: the plugin has done something to resolve the 404
|
554
|
+
situation, and copyparty should reattempt reading the file.
|
555
|
+
if it still fails, a regular 404 will be returned
|
556
|
+
|
557
|
+
> \033[32m"allow"\033[0m: should ignore the insufficient permissions
|
558
|
+
and let the client continue anyways
|
559
|
+
|
560
|
+
> \033[32m""\033[0m: the plugin has not handled the request;
|
561
|
+
try the next plugin or return the usual 404 or 403
|
562
|
+
|
563
|
+
\033[1;35mPS!\033[0m the folder that contains the python file should ideally
|
564
|
+
not contain many other python files, and especially nothing
|
565
|
+
with filenames that overlap with modules used by copyparty
|
566
|
+
"""
|
567
|
+
),
|
568
|
+
],
|
525
569
|
[
|
526
570
|
"hooks",
|
527
571
|
"execute commands before/after various events",
|
@@ -852,6 +896,13 @@ def add_smb(ap):
|
|
852
896
|
ap2.add_argument("--smbvvv", action="store_true", help="verbosest")
|
853
897
|
|
854
898
|
|
899
|
+
def add_handlers(ap):
|
900
|
+
ap2 = ap.add_argument_group('handlers (see --help-handlers)')
|
901
|
+
ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="handle 404s by executing PY file")
|
902
|
+
ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="handle 403s by executing PY file")
|
903
|
+
ap2.add_argument("--hot-handlers", action="store_true", help="reload handlers on each request -- expensive but convenient when hacking on stuff")
|
904
|
+
|
905
|
+
|
855
906
|
def add_hooks(ap):
|
856
907
|
ap2 = ap.add_argument_group('event hooks (see --help-hooks)')
|
857
908
|
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute CMD before a file upload starts")
|
@@ -1107,6 +1158,7 @@ def run_argparse(
|
|
1107
1158
|
add_optouts(ap)
|
1108
1159
|
add_shutdown(ap)
|
1109
1160
|
add_yolo(ap)
|
1161
|
+
add_handlers(ap)
|
1110
1162
|
add_hooks(ap)
|
1111
1163
|
add_ui(ap, retry)
|
1112
1164
|
add_admin(ap)
|
@@ -1254,7 +1306,7 @@ def main(argv = None) :
|
|
1254
1306
|
elif not al.no_ansi:
|
1255
1307
|
al.ansi = VT100
|
1256
1308
|
|
1257
|
-
if WINDOWS and not al.keep_qem:
|
1309
|
+
if WINDOWS and not al.keep_qem and not al.ah_cli:
|
1258
1310
|
try:
|
1259
1311
|
disable_quickedit()
|
1260
1312
|
except:
|
@@ -1040,7 +1040,7 @@ class AuthSrv(object):
|
|
1040
1040
|
flags[name] = True
|
1041
1041
|
return
|
1042
1042
|
|
1043
|
-
if name not in "mtp xbu xau xiu xbr xar xbd xad xm".split():
|
1043
|
+
if name not in "mtp xbu xau xiu xbr xar xbd xad xm on404 on403".split():
|
1044
1044
|
if value is True:
|
1045
1045
|
t = "└─add volflag [{}] = {} ({})"
|
1046
1046
|
else:
|
@@ -1439,7 +1439,7 @@ class AuthSrv(object):
|
|
1439
1439
|
|
1440
1440
|
# append additive args from argv to volflags
|
1441
1441
|
hooks = "xbu xau xiu xbr xar xbd xad xm".split()
|
1442
|
-
for name in
|
1442
|
+
for name in "mtp on404 on403".split() + hooks:
|
1443
1443
|
self._read_volflag(vol.flags, name, getattr(self.args, name), True)
|
1444
1444
|
|
1445
1445
|
for hn in hooks:
|
@@ -1828,7 +1828,7 @@ class AuthSrv(object):
|
|
1828
1828
|
]
|
1829
1829
|
|
1830
1830
|
csv = set("i p".split())
|
1831
|
-
lst = set("c ihead mtm mtp xad xar xau xiu xbd xbr xbu xm".split())
|
1831
|
+
lst = set("c ihead mtm mtp xad xar xau xiu xbd xbr xbu xm on404 on403".split())
|
1832
1832
|
askip = set("a v c vc cgen theme".split())
|
1833
1833
|
|
1834
1834
|
# keymap from argv to vflag
|
@@ -125,6 +125,10 @@ flagcats = {
|
|
125
125
|
"dathumb": "disables audio thumbnails (spectrograms)",
|
126
126
|
"dithumb": "disables image thumbnails",
|
127
127
|
},
|
128
|
+
"handlers\n(better explained in --help-handlers)": {
|
129
|
+
"on404=PY": "handle 404s by executing PY file",
|
130
|
+
"on403=PY": "handle 403s by executing PY file",
|
131
|
+
},
|
128
132
|
"event hooks\n(better explained in --help-hooks)": {
|
129
133
|
"xbu=CMD": "execute CMD before a file upload starts",
|
130
134
|
"xau=CMD": "execute CMD after a file upload finishes",
|
@@ -58,6 +58,7 @@ from .util import (
|
|
58
58
|
html_escape,
|
59
59
|
humansize,
|
60
60
|
ipnorm,
|
61
|
+
loadpy,
|
61
62
|
min_ex,
|
62
63
|
quotep,
|
63
64
|
rand_name,
|
@@ -763,11 +764,27 @@ class HttpCli(object):
|
|
763
764
|
return True
|
764
765
|
|
765
766
|
if not self.can_read and not self.can_write and not self.can_get:
|
766
|
-
|
767
|
-
|
768
|
-
|
767
|
+
t = "@{} has no access to [{}]"
|
768
|
+
self.log(t.format(self.uname, self.vpath))
|
769
|
+
|
770
|
+
if self.avn and "on403" in self.avn.flags:
|
771
|
+
vn, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False)
|
772
|
+
ret = self.on40x(vn.flags["on403"], vn, rem)
|
773
|
+
if ret == "true":
|
774
|
+
return True
|
775
|
+
elif ret == "false":
|
776
|
+
return False
|
777
|
+
elif ret == "allow":
|
778
|
+
self.log("plugin override; access permitted")
|
779
|
+
self.can_read = self.can_write = self.can_move = True
|
780
|
+
self.can_delete = self.can_get = self.can_upget = True
|
781
|
+
else:
|
782
|
+
return self.tx_404(True)
|
783
|
+
else:
|
784
|
+
if self.vpath:
|
785
|
+
return self.tx_404(True)
|
769
786
|
|
770
|
-
|
787
|
+
self.uparam["h"] = ""
|
771
788
|
|
772
789
|
if "tree" in self.uparam:
|
773
790
|
return self.tx_tree()
|
@@ -3052,6 +3069,20 @@ class HttpCli(object):
|
|
3052
3069
|
self.reply(html.encode("utf-8"), status=rc)
|
3053
3070
|
return True
|
3054
3071
|
|
3072
|
+
def on40x(self, mods , vn , rem ) :
|
3073
|
+
for mpath in mods:
|
3074
|
+
try:
|
3075
|
+
mod = loadpy(mpath, self.args.hot_handlers)
|
3076
|
+
except Exception as ex:
|
3077
|
+
self.log("import failed: {!r}".format(ex))
|
3078
|
+
continue
|
3079
|
+
|
3080
|
+
ret = mod.main(self, vn, rem)
|
3081
|
+
if ret:
|
3082
|
+
return ret.lower()
|
3083
|
+
|
3084
|
+
return "" # unhandled / fallthrough
|
3085
|
+
|
3055
3086
|
def scanvol(self) :
|
3056
3087
|
if not self.can_read or not self.can_write:
|
3057
3088
|
raise Pebkac(403, "not allowed for user " + self.uname)
|
@@ -3369,7 +3400,21 @@ class HttpCli(object):
|
|
3369
3400
|
try:
|
3370
3401
|
st = bos.stat(abspath)
|
3371
3402
|
except:
|
3372
|
-
|
3403
|
+
if "on404" not in vn.flags:
|
3404
|
+
return self.tx_404()
|
3405
|
+
|
3406
|
+
ret = self.on40x(vn.flags["on404"], vn, rem)
|
3407
|
+
if ret == "true":
|
3408
|
+
return True
|
3409
|
+
elif ret == "false":
|
3410
|
+
return False
|
3411
|
+
elif ret == "retry":
|
3412
|
+
try:
|
3413
|
+
st = bos.stat(abspath)
|
3414
|
+
except:
|
3415
|
+
return self.tx_404()
|
3416
|
+
else:
|
3417
|
+
return self.tx_404()
|
3373
3418
|
|
3374
3419
|
if rem.startswith(".hist/up2k.") or (
|
3375
3420
|
rem.endswith("/dir.txt") and rem.startswith(".hist/th/")
|
@@ -35,7 +35,7 @@ class Ico(object):
|
|
35
35
|
h = int(100 / (float(sw) / float(sh)))
|
36
36
|
w = 100
|
37
37
|
|
38
|
-
if chrome
|
38
|
+
if chrome:
|
39
39
|
# cannot handle more than ~2000 unique SVGs
|
40
40
|
if HAVE_PIL:
|
41
41
|
# svg: 3s, cache: 6s, this: 8s
|
@@ -45,8 +45,19 @@ class Ico(object):
|
|
45
45
|
w = 64
|
46
46
|
img = Image.new("RGB", (w, h), "#" + c[:6])
|
47
47
|
pb = ImageDraw.Draw(img)
|
48
|
-
|
49
|
-
|
48
|
+
try:
|
49
|
+
_, _, tw, th = pb.textbbox((0, 0), ext)
|
50
|
+
except:
|
51
|
+
tw, th = pb.textsize(ext)
|
52
|
+
|
53
|
+
tw += len(ext)
|
54
|
+
cw = tw // len(ext)
|
55
|
+
x = ((w - tw) // 2) - (cw * 2) // 3
|
56
|
+
fill = "#" + c[6:]
|
57
|
+
for ch in ext:
|
58
|
+
pb.text((x, (h - th) // 2), " %s " % (ch,), fill=fill)
|
59
|
+
x += cw
|
60
|
+
|
50
61
|
img = img.resize((w * 3, h * 3), Image.NEAREST)
|
51
62
|
|
52
63
|
buf = BytesIO()
|
@@ -2711,6 +2711,34 @@ def runhook(
|
|
2711
2711
|
return True
|
2712
2712
|
|
2713
2713
|
|
2714
|
+
def loadpy(ap , hot ) :
|
2715
|
+
"""
|
2716
|
+
a nice can of worms capable of causing all sorts of bugs
|
2717
|
+
depending on what other inconveniently named files happen
|
2718
|
+
to be in the same folder
|
2719
|
+
"""
|
2720
|
+
if ap.startswith("~"):
|
2721
|
+
ap = os.path.expanduser(ap)
|
2722
|
+
|
2723
|
+
mdir, mfile = os.path.split(absreal(ap))
|
2724
|
+
mname = mfile.rsplit(".", 1)[0]
|
2725
|
+
sys.path.insert(0, mdir)
|
2726
|
+
|
2727
|
+
if PY2:
|
2728
|
+
mod = __import__(mname)
|
2729
|
+
if hot:
|
2730
|
+
reload(mod)
|
2731
|
+
else:
|
2732
|
+
import importlib
|
2733
|
+
|
2734
|
+
mod = importlib.import_module(mname)
|
2735
|
+
if hot:
|
2736
|
+
importlib.reload(mod)
|
2737
|
+
|
2738
|
+
sys.path.remove(mdir)
|
2739
|
+
return mod
|
2740
|
+
|
2741
|
+
|
2714
2742
|
def gzip_orig_sz(fn ) :
|
2715
2743
|
with open(fsenc(fn), "rb") as f:
|
2716
2744
|
f.seek(-4, 2)
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.8.
|
3
|
+
Version: 1.8.1
|
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
|
@@ -109,12 +109,14 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
109
109
|
* [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
|
110
110
|
* [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
|
111
111
|
* [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
|
112
|
+
* [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
|
112
113
|
* [hiding from google](#hiding-from-google) - tell search engines you dont wanna be indexed
|
113
114
|
* [themes](#themes)
|
114
115
|
* [complete examples](#complete-examples)
|
115
116
|
* [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
|
116
117
|
* [packages](#packages) - the party might be closer than you think
|
117
118
|
* [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
119
|
+
* [fedora package](#fedora-package) - now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/)
|
118
120
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
119
121
|
* [nixos module](#nixos-module)
|
120
122
|
* [browser support](#browser-support) - TLDR: yes
|
@@ -1169,6 +1171,13 @@ note that this is way more complicated than the new [event hooks](#event-hooks)
|
|
1169
1171
|
note that it will occupy the parsing threads, so fork anything expensive (or set `kn` to have copyparty fork it for you) -- otoh if you want to intentionally queue/singlethread you can combine it with `--mtag-mt 1`
|
1170
1172
|
|
1171
1173
|
|
1174
|
+
## handlers
|
1175
|
+
|
1176
|
+
redefine behavior with plugins ([examples](./bin/handlers/))
|
1177
|
+
|
1178
|
+
replace 404 and 403 errors with something completely different (that's it for now)
|
1179
|
+
|
1180
|
+
|
1172
1181
|
## hiding from google
|
1173
1182
|
|
1174
1183
|
tell search engines you dont wanna be indexed, either using the good old [robots.txt](https://www.robotstxt.org/robotstxt.html) or through copyparty settings:
|
@@ -1271,6 +1280,19 @@ the party might be closer than you think
|
|
1271
1280
|
now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
|
1272
1281
|
|
1273
1282
|
|
1283
|
+
## fedora package
|
1284
|
+
|
1285
|
+
now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/) , maintained autonomously -- [track record](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/package/python-copyparty/) seems OK
|
1286
|
+
|
1287
|
+
```bash
|
1288
|
+
dnf copr enable @copr/PyPI
|
1289
|
+
dnf install python3-copyparty # just a minimal install, or...
|
1290
|
+
dnf install python3-{copyparty,pillow,argon2-cffi,pyftpdlib,pyOpenSSL} ffmpeg-free # with recommended deps
|
1291
|
+
```
|
1292
|
+
|
1293
|
+
this *may* also work on RHEL but [I'm not paying IBM to verify that](https://www.jeffgeerling.com/blog/2023/dear-red-hat-are-you-dumb)
|
1294
|
+
|
1295
|
+
|
1274
1296
|
## nix package
|
1275
1297
|
|
1276
1298
|
`nix profile install github:9001/copyparty`
|
Binary file
|
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
|