copyparty 1.16.8__py3-none-any.whl → 1.16.10__py3-none-any.whl
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/__main__.py +34 -13
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +8 -1
- copyparty/cfg.py +6 -0
- copyparty/dxml.py +48 -3
- copyparty/httpcli.py +40 -9
- copyparty/svchub.py +13 -0
- copyparty/th_cli.py +6 -2
- copyparty/th_srv.py +100 -41
- copyparty/up2k.py +11 -5
- copyparty/util.py +163 -8
- copyparty/web/a/u2c.py +3 -3
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/md.js.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- copyparty/web/svcs.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/METADATA +51 -10
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/RECORD +26 -26
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/LICENSE +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/WHEEL +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/entry_points.txt +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.10.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -54,6 +54,8 @@ from .util import (
|
|
54
54
|
RAM_TOTAL,
|
55
55
|
SQLITE_VER,
|
56
56
|
UNPLICATIONS,
|
57
|
+
URL_BUG,
|
58
|
+
URL_PRJ,
|
57
59
|
Daemon,
|
58
60
|
align_tab,
|
59
61
|
ansi_re,
|
@@ -326,17 +328,16 @@ def ensure_webdeps() :
|
|
326
328
|
if has_resource(E, "web/deps/mini-fa.woff"):
|
327
329
|
return
|
328
330
|
|
329
|
-
|
330
|
-
"""could not find webdeps;
|
331
|
+
t = """could not find webdeps;
|
331
332
|
if you are running the sfx, or exe, or pypi package, or docker image,
|
332
333
|
then this is a bug! Please let me know so I can fix it, thanks :-)
|
333
|
-
|
334
|
+
%s
|
334
335
|
|
335
336
|
however, if you are a dev, or running copyparty from source, and you want
|
336
337
|
full client functionality, you will need to build or obtain the webdeps:
|
337
|
-
|
338
|
+
%s/blob/hovudstraum/docs/devnotes.md#building
|
338
339
|
"""
|
339
|
-
)
|
340
|
+
warn(t % (URL_BUG, URL_PRJ))
|
340
341
|
|
341
342
|
|
342
343
|
def configure_ssl_ver(al ) :
|
@@ -731,6 +732,10 @@ def get_sects():
|
|
731
732
|
the \033[33m,,\033[35m stops copyparty from reading the rest as flags and
|
732
733
|
the \033[33m--\033[35m stops notify-send from reading the message as args
|
733
734
|
and the alert will be "hey" followed by the messagetext
|
735
|
+
|
736
|
+
\033[36m--xau zmq:pub:tcp://*:5556\033[35m announces uploads on zeromq;
|
737
|
+
\033[36m--xau t3,zmq:push:tcp://*:5557\033[35m also works, and you can
|
738
|
+
\033[36m--xau t3,j,zmq:req:tcp://localhost:5555\033[35m too for example
|
734
739
|
\033[0m
|
735
740
|
each hook is executed once for each event, except for \033[36mxiu\033[0m
|
736
741
|
which builds up a backlog of uploads, running the hook just once
|
@@ -762,11 +767,22 @@ def get_sects():
|
|
762
767
|
values for --urlform:
|
763
768
|
\033[36mstash\033[35m dumps the data to file and returns length + checksum
|
764
769
|
\033[36msave,get\033[35m dumps to file and returns the page like a GET
|
765
|
-
\033[36mprint
|
766
|
-
|
770
|
+
\033[36mprint \033[35m prints the data to log and returns an error
|
771
|
+
\033[36mprint,xm \033[35m prints the data to log and returns --xm output
|
772
|
+
\033[36mprint,get\033[35m prints the data to log and returns GET\033[0m
|
773
|
+
|
774
|
+
note that the \033[35m--xm\033[0m hook will only run if \033[35m--urlform\033[0m is
|
775
|
+
either \033[36mprint\033[0m or \033[36mprint,get\033[0m or the default \033[36mprint,xm\033[0m
|
776
|
+
|
777
|
+
if an \033[35m--xm\033[0m hook returns text, then
|
778
|
+
the response code will be HTTP 202;
|
779
|
+
http/get responses will be HTTP 200
|
780
|
+
|
781
|
+
if there are multiple \033[35m--xm\033[0m hooks defined, then
|
782
|
+
the first hook that produced output is returned
|
767
783
|
|
768
|
-
|
769
|
-
|
784
|
+
if there are no \033[35m--xm\033[0m hooks defined, then the default
|
785
|
+
\033[36mprint,xm\033[0m behaves like \033[36mprint,get\033[0m (returning html)
|
770
786
|
"""
|
771
787
|
),
|
772
788
|
],
|
@@ -947,7 +963,7 @@ def add_general(ap, nc, srvname):
|
|
947
963
|
ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
|
948
964
|
ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
|
949
965
|
ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)")
|
950
|
-
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,
|
966
|
+
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
|
951
967
|
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
|
952
968
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
953
969
|
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
@@ -1320,6 +1336,7 @@ def add_admin(ap):
|
|
1320
1336
|
ap2.add_argument("--no-ups-page", action="store_true", help="disable ?ru (list of recent uploads)")
|
1321
1337
|
ap2.add_argument("--no-up-list", action="store_true", help="don't show list of incoming files in controlpanel")
|
1322
1338
|
ap2.add_argument("--dl-list", metavar="LVL", type=int, default=2, help="who can see active downloads in the controlpanel? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone")
|
1339
|
+
ap2.add_argument("--ups-who", metavar="LVL", type=int, default=2, help="who can see recent uploads on the ?ru page? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone (volflag=ups_who)")
|
1323
1340
|
ap2.add_argument("--ups-when", action="store_true", help="let everyone see upload timestamps on the ?ru page, not just admins")
|
1324
1341
|
|
1325
1342
|
|
@@ -1360,6 +1377,8 @@ def add_transcoding(ap):
|
|
1360
1377
|
ap2 = ap.add_argument_group('transcoding options')
|
1361
1378
|
ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable")
|
1362
1379
|
ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable")
|
1380
|
+
ap2.add_argument("--no-caf", action="store_true", help="disable transcoding to caf-opus (affects iOS v12~v17), will use mp3 instead")
|
1381
|
+
ap2.add_argument("--no-owa", action="store_true", help="disable transcoding to webm-opus (iOS v18 and later), will use mp3 instead")
|
1363
1382
|
ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding")
|
1364
1383
|
ap2.add_argument("--no-bacode", action="store_true", help="disable batch audio transcoding by folder download (zip/tar)")
|
1365
1384
|
ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
|
@@ -1468,12 +1487,14 @@ def add_ui(ap, retry):
|
|
1468
1487
|
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)")
|
1469
1488
|
ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
|
1470
1489
|
ap2.add_argument("--bname", metavar="TXT", type=u, default="--name", help="server name (displayed in filebrowser document title)")
|
1471
|
-
ap2.add_argument("--pb-url", metavar="URL", type=u, default=
|
1490
|
+
ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-np\033[0m")
|
1472
1491
|
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
|
1473
1492
|
ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
|
1474
1493
|
ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
|
1475
|
-
ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to
|
1476
|
-
ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to
|
1494
|
+
ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox")
|
1495
|
+
ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs (volflag=lg_sbf)")
|
1496
|
+
ap2.add_argument("--md-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for README.md docs, for example [\033[32mfullscreen\033[0m] (volflag=md_sba)")
|
1497
|
+
ap2.add_argument("--lg-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for prologue/epilogue docs (volflag=lg_sba); see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#iframes")
|
1477
1498
|
ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
|
1478
1499
|
ap2.add_argument("--no-sb-lg", action="store_true", help="don't sandbox prologue/epilogue docs (volflags: no_sb_lg | sb_lg); enables non-js support")
|
1479
1500
|
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -1825,7 +1825,11 @@ class AuthSrv(object):
|
|
1825
1825
|
if fka and not fk:
|
1826
1826
|
fk = fka
|
1827
1827
|
if fk:
|
1828
|
-
|
1828
|
+
fk = 8 if fk is True else int(fk)
|
1829
|
+
if fk > 72:
|
1830
|
+
t = "max filekey-length is 72; volume /%s specified %d (anything higher than 16 is pointless btw)"
|
1831
|
+
raise Exception(t % (vol.vpath, fk))
|
1832
|
+
vol.flags["fk"] = fk
|
1829
1833
|
have_fk = True
|
1830
1834
|
|
1831
1835
|
dk = vol.flags.get("dk")
|
@@ -2332,6 +2336,7 @@ class AuthSrv(object):
|
|
2332
2336
|
"frand": bool(vf.get("rand")),
|
2333
2337
|
"lifetime": vf.get("lifetime") or 0,
|
2334
2338
|
"unlist": vf.get("unlist") or "",
|
2339
|
+
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
|
2335
2340
|
}
|
2336
2341
|
js_htm = {
|
2337
2342
|
"s_name": self.args.bname,
|
@@ -2344,6 +2349,8 @@ class AuthSrv(object):
|
|
2344
2349
|
"have_unpost": int(self.args.unpost),
|
2345
2350
|
"have_emp": self.args.emp,
|
2346
2351
|
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
2352
|
+
"sba_md": vf.get("md_sba") or "",
|
2353
|
+
"sba_lg": vf.get("lg_sba") or "",
|
2347
2354
|
"txt_ext": self.args.textfiles.replace(",", " "),
|
2348
2355
|
"def_hcols": list(vf.get("mth") or []),
|
2349
2356
|
"unlist0": vf.get("unlist") or "",
|
copyparty/cfg.py
CHANGED
@@ -74,6 +74,8 @@ def vf_vmap() :
|
|
74
74
|
"html_head",
|
75
75
|
"lg_sbf",
|
76
76
|
"md_sbf",
|
77
|
+
"lg_sba",
|
78
|
+
"md_sba",
|
77
79
|
"nrand",
|
78
80
|
"og_desc",
|
79
81
|
"og_site",
|
@@ -91,6 +93,7 @@ def vf_vmap() :
|
|
91
93
|
"unlist",
|
92
94
|
"u2abort",
|
93
95
|
"u2ts",
|
96
|
+
"ups_who",
|
94
97
|
):
|
95
98
|
ret[k] = k
|
96
99
|
return ret
|
@@ -144,6 +147,7 @@ flagcats = {
|
|
144
147
|
"noclone": "take dupe data from clients, even if available on HDD",
|
145
148
|
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
146
149
|
"sparse": "force use of sparse files, mainly for s3-backed storage",
|
150
|
+
"nosparse": "deny use of sparse files, mainly for slow storage",
|
147
151
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
148
152
|
"nosub": "forces all uploads into the top folder of the vfs",
|
149
153
|
"magic": "enables filetype detection for nameless uploads",
|
@@ -240,6 +244,8 @@ flagcats = {
|
|
240
244
|
"sb_lg": "enable js sandbox for prologue/epilogue (default)",
|
241
245
|
"md_sbf": "list of markdown-sandbox safeguards to disable",
|
242
246
|
"lg_sbf": "list of *logue-sandbox safeguards to disable",
|
247
|
+
"md_sba": "value of iframe allow-prop for markdown-sandbox",
|
248
|
+
"lg_sba": "value of iframe allow-prop for *logue-sandbox",
|
243
249
|
"nohtml": "return html and markdown as text/html",
|
244
250
|
},
|
245
251
|
"others": {
|
copyparty/dxml.py
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from __future__ import print_function, unicode_literals
|
3
|
+
|
1
4
|
import importlib
|
2
5
|
import sys
|
3
6
|
import xml.etree.ElementTree as ET
|
4
7
|
|
5
8
|
from .__init__ import PY2
|
6
9
|
|
10
|
+
class BadXML(Exception):
|
11
|
+
pass
|
12
|
+
|
13
|
+
|
7
14
|
def get_ET() :
|
8
15
|
pn = "xml.etree.ElementTree"
|
9
16
|
cn = "_elementtree"
|
@@ -30,7 +37,7 @@ def get_ET() :
|
|
30
37
|
XMLParser = get_ET()
|
31
38
|
|
32
39
|
|
33
|
-
class
|
40
|
+
class _DXMLParser(XMLParser): # type: ignore
|
34
41
|
def __init__(self) :
|
35
42
|
tb = ET.TreeBuilder()
|
36
43
|
super(DXMLParser, self).__init__(target=tb)
|
@@ -45,8 +52,12 @@ class DXMLParser(XMLParser): # type: ignore
|
|
45
52
|
raise BadXML("{}, {}".format(a, ka))
|
46
53
|
|
47
54
|
|
48
|
-
class
|
49
|
-
|
55
|
+
class _NG(XMLParser): # type: ignore
|
56
|
+
def __int__(self) :
|
57
|
+
raise BadXML("dxml selftest failed")
|
58
|
+
|
59
|
+
|
60
|
+
DXMLParser = _DXMLParser
|
50
61
|
|
51
62
|
|
52
63
|
def parse_xml(txt ) :
|
@@ -55,6 +66,40 @@ def parse_xml(txt ) :
|
|
55
66
|
return parser.close() # type: ignore
|
56
67
|
|
57
68
|
|
69
|
+
def selftest() :
|
70
|
+
qbe = r"""<!DOCTYPE d [
|
71
|
+
<!ENTITY a "nice_bakuretsu">
|
72
|
+
]>
|
73
|
+
<root>&a;&a;&a;</root>"""
|
74
|
+
|
75
|
+
emb = r"""<!DOCTYPE d [
|
76
|
+
<!ENTITY a SYSTEM "file:///etc/hostname">
|
77
|
+
]>
|
78
|
+
<root>&a;</root>"""
|
79
|
+
|
80
|
+
# future-proofing; there's never been any known vulns
|
81
|
+
# regarding DTDs and ET.XMLParser, but might as well
|
82
|
+
# block them since webdav-clients don't use them
|
83
|
+
dtd = r"""<!DOCTYPE d SYSTEM "a.dtd">
|
84
|
+
<root>a</root>"""
|
85
|
+
|
86
|
+
for txt in (qbe, emb, dtd):
|
87
|
+
try:
|
88
|
+
parse_xml(txt)
|
89
|
+
t = "WARNING: dxml selftest failed:\n%s\n"
|
90
|
+
print(t % (txt,), file=sys.stderr)
|
91
|
+
return False
|
92
|
+
except BadXML:
|
93
|
+
pass
|
94
|
+
|
95
|
+
return True
|
96
|
+
|
97
|
+
|
98
|
+
DXML_OK = selftest()
|
99
|
+
if not DXML_OK:
|
100
|
+
DXMLParser = _NG
|
101
|
+
|
102
|
+
|
58
103
|
def mktnod(name , text ) :
|
59
104
|
el = ET.Element(name)
|
60
105
|
el.text = text
|
copyparty/httpcli.py
CHANGED
@@ -128,6 +128,8 @@ NO_CACHE = {"Cache-Control": "no-cache"}
|
|
128
128
|
|
129
129
|
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
|
130
130
|
|
131
|
+
BADXFF = " due to dangerous misconfiguration (the http-header specified by --xff-hdr was received from an untrusted reverse-proxy)"
|
132
|
+
|
131
133
|
H_CONN_KEEPALIVE = "Connection: Keep-Alive"
|
132
134
|
H_CONN_CLOSE = "Connection: Close"
|
133
135
|
|
@@ -157,6 +159,8 @@ class HttpCli(object):
|
|
157
159
|
|
158
160
|
def __init__(self, conn ) :
|
159
161
|
|
162
|
+
empty_stringlist = []
|
163
|
+
|
160
164
|
self.t0 = time.time()
|
161
165
|
self.conn = conn
|
162
166
|
self.u2mutex = conn.u2mutex # mypy404
|
@@ -202,9 +206,7 @@ class HttpCli(object):
|
|
202
206
|
self.trailing_slash = True
|
203
207
|
self.uname = " "
|
204
208
|
self.pw = " "
|
205
|
-
self.rvol =
|
206
|
-
self.wvol = [" "]
|
207
|
-
self.avol = [" "]
|
209
|
+
self.rvol = self.wvol = self.avol = empty_stringlist
|
208
210
|
self.do_log = True
|
209
211
|
self.can_read = False
|
210
212
|
self.can_write = False
|
@@ -385,6 +387,7 @@ class HttpCli(object):
|
|
385
387
|
) + "0.0/16"
|
386
388
|
zs2 = ' or "--xff-src=lan"' if self.conn.xff_lan.map(pip) else ""
|
387
389
|
self.log(t % (self.args.xff_hdr, pip, cli_ip, zso, zs, zs2), 3)
|
390
|
+
self.bad_xff = True
|
388
391
|
else:
|
389
392
|
self.ip = cli_ip
|
390
393
|
self.is_vproxied = bool(self.args.R)
|
@@ -505,7 +508,7 @@ class HttpCli(object):
|
|
505
508
|
return False
|
506
509
|
|
507
510
|
if "k" in uparam:
|
508
|
-
m =
|
511
|
+
m = re_k.search(uparam["k"])
|
509
512
|
if m:
|
510
513
|
zs = uparam["k"]
|
511
514
|
t = "malicious user; illegal filekey; req(%r) k(%r) => %r"
|
@@ -1888,6 +1891,9 @@ class HttpCli(object):
|
|
1888
1891
|
if "stash" in opt:
|
1889
1892
|
return self.handle_stash(False)
|
1890
1893
|
|
1894
|
+
xm = []
|
1895
|
+
xm_rsp = {}
|
1896
|
+
|
1891
1897
|
if "save" in opt:
|
1892
1898
|
post_sz, _, _, _, _, path, _ = self.dump_to_file(False)
|
1893
1899
|
self.log("urlform: %d bytes, %r" % (post_sz, path))
|
@@ -1910,7 +1916,7 @@ class HttpCli(object):
|
|
1910
1916
|
plain = plain[4:]
|
1911
1917
|
xm = self.vn.flags.get("xm")
|
1912
1918
|
if xm:
|
1913
|
-
runhook(
|
1919
|
+
xm_rsp = runhook(
|
1914
1920
|
self.log,
|
1915
1921
|
self.conn.hsrv.broker,
|
1916
1922
|
None,
|
@@ -1934,6 +1940,13 @@ class HttpCli(object):
|
|
1934
1940
|
except Exception as ex:
|
1935
1941
|
self.log(repr(ex))
|
1936
1942
|
|
1943
|
+
if "xm" in opt:
|
1944
|
+
if xm:
|
1945
|
+
self.loud_reply(xm_rsp.get("stdout") or "", status=202)
|
1946
|
+
return True
|
1947
|
+
else:
|
1948
|
+
return self.handle_get()
|
1949
|
+
|
1937
1950
|
if "get" in opt:
|
1938
1951
|
return self.handle_get()
|
1939
1952
|
|
@@ -4334,7 +4347,7 @@ class HttpCli(object):
|
|
4334
4347
|
self.log,
|
4335
4348
|
self.asrv,
|
4336
4349
|
fgen,
|
4337
|
-
utf8="utf" in uarg,
|
4350
|
+
utf8="utf" in uarg or not uarg,
|
4338
4351
|
pre_crc="crc" in uarg,
|
4339
4352
|
cmp=uarg if cancmp or uarg == "pax" else "",
|
4340
4353
|
)
|
@@ -4982,8 +4995,16 @@ class HttpCli(object):
|
|
4982
4995
|
and (self.uname in vol.axs.uread or self.uname in vol.axs.upget)
|
4983
4996
|
}
|
4984
4997
|
|
4998
|
+
bad_xff = hasattr(self, "bad_xff")
|
4999
|
+
if bad_xff:
|
5000
|
+
allvols = []
|
5001
|
+
t = "will not return list of recent uploads" + BADXFF
|
5002
|
+
self.log(t, 1)
|
5003
|
+
if self.avol:
|
5004
|
+
raise Pebkac(500, t)
|
5005
|
+
|
4985
5006
|
x = self.conn.hsrv.broker.ask(
|
4986
|
-
"up2k.get_unfinished_by_user", self.uname, self.ip
|
5007
|
+
"up2k.get_unfinished_by_user", self.uname, "" if bad_xff else self.ip
|
4987
5008
|
)
|
4988
5009
|
uret = x.get()
|
4989
5010
|
|
@@ -5109,6 +5130,12 @@ class HttpCli(object):
|
|
5109
5130
|
adm = "*" in vol.axs.uadmin or self.uname in vol.axs.uadmin
|
5110
5131
|
dots = "*" in vol.axs.udot or self.uname in vol.axs.udot
|
5111
5132
|
|
5133
|
+
lvl = int(vol.flags["ups_who"])
|
5134
|
+
if not lvl:
|
5135
|
+
continue
|
5136
|
+
elif lvl == 1 and not adm:
|
5137
|
+
continue
|
5138
|
+
|
5112
5139
|
n = 1000
|
5113
5140
|
q = "select sz, rd, fn, ip, at from up where at>0 order by at desc"
|
5114
5141
|
for sz, rd, fn, ip, at in cur.execute(q):
|
@@ -5377,12 +5404,16 @@ class HttpCli(object):
|
|
5377
5404
|
if self.args.no_del:
|
5378
5405
|
raise Pebkac(403, "the delete feature is disabled in server config")
|
5379
5406
|
|
5407
|
+
unpost = "unpost" in self.uparam
|
5408
|
+
if unpost and hasattr(self, "bad_xff"):
|
5409
|
+
self.log("unpost was denied" + BADXFF, 1)
|
5410
|
+
raise Pebkac(403, "the delete feature is disabled in server config")
|
5411
|
+
|
5380
5412
|
if not req:
|
5381
5413
|
req = [self.vpath]
|
5382
5414
|
elif self.is_vproxied:
|
5383
5415
|
req = [x[len(self.args.SR) :] for x in req]
|
5384
5416
|
|
5385
|
-
unpost = "unpost" in self.uparam
|
5386
5417
|
nlim = int(self.uparam.get("lim") or 0)
|
5387
5418
|
lim = [nlim, nlim] if nlim else []
|
5388
5419
|
|
@@ -5782,7 +5813,7 @@ class HttpCli(object):
|
|
5782
5813
|
"taglist": [],
|
5783
5814
|
"have_tags_idx": int(e2t),
|
5784
5815
|
"have_b_u": (self.can_write and self.uparam.get("b") == "u"),
|
5785
|
-
"sb_lg":
|
5816
|
+
"sb_lg": vn.js_ls["sb_lg"],
|
5786
5817
|
"url_suf": url_suf,
|
5787
5818
|
"title": html_escape("%s %s" % (self.args.bname, self.vpath), crlf=True),
|
5788
5819
|
"srv_info": srv_infot,
|
copyparty/svchub.py
CHANGED
@@ -44,6 +44,8 @@ from .util import (
|
|
44
44
|
FFMPEG_URL,
|
45
45
|
HAVE_PSUTIL,
|
46
46
|
HAVE_SQLITE3,
|
47
|
+
HAVE_ZMQ,
|
48
|
+
URL_BUG,
|
47
49
|
UTC,
|
48
50
|
VERSIONS,
|
49
51
|
Daemon,
|
@@ -54,6 +56,7 @@ from .util import (
|
|
54
56
|
alltrace,
|
55
57
|
ansi_re,
|
56
58
|
build_netmap,
|
59
|
+
expat_ver,
|
57
60
|
load_ipu,
|
58
61
|
min_ex,
|
59
62
|
mp,
|
@@ -629,6 +632,7 @@ class SvcHub(object):
|
|
629
632
|
(HAVE_FFPROBE, "ffprobe", t_ff + ", read audio/media tags"),
|
630
633
|
(HAVE_MUTAGEN, "mutagen", "read audio tags (ffprobe is better but slower)"),
|
631
634
|
(HAVE_ARGON2, "argon2", "secure password hashing (advanced users only)"),
|
635
|
+
(HAVE_ZMQ, "pyzmq", "send zeromq messages from event-hooks"),
|
632
636
|
(HAVE_HEIF, "pillow-heif", "read .heif images with pillow (rarely useful)"),
|
633
637
|
(HAVE_AVIF, "pillow-avif", "read .avif images with pillow (rarely useful)"),
|
634
638
|
]
|
@@ -685,6 +689,15 @@ class SvcHub(object):
|
|
685
689
|
if self.args.bauth_last:
|
686
690
|
self.log("root", "WARNING: ignoring --bauth-last due to --no-bauth", 3)
|
687
691
|
|
692
|
+
if not self.args.no_dav:
|
693
|
+
from .dxml import DXML_OK
|
694
|
+
|
695
|
+
if not DXML_OK:
|
696
|
+
if not self.args.no_dav:
|
697
|
+
self.args.no_dav = True
|
698
|
+
t = "WARNING:\nDisabling WebDAV support because dxml selftest failed. Please report this bug;\n%s\n...and include the following information in the bug-report:\n%s | expat %s\n"
|
699
|
+
self.log("root", t % (URL_BUG, VERSIONS, expat_ver()), 1)
|
700
|
+
|
688
701
|
def _process_config(self) :
|
689
702
|
al = self.args
|
690
703
|
|
copyparty/th_cli.py
CHANGED
@@ -6,7 +6,7 @@ import os
|
|
6
6
|
from .__init__ import TYPE_CHECKING
|
7
7
|
from .authsrv import VFS
|
8
8
|
from .bos import bos
|
9
|
-
from .th_srv import HAVE_WEBP, thumb_path
|
9
|
+
from .th_srv import EXTS_AC, HAVE_WEBP, thumb_path
|
10
10
|
from .util import Cooldown
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
@@ -54,13 +54,17 @@ class ThumbCli(object):
|
|
54
54
|
if is_vid and "dvthumb" in dbv.flags:
|
55
55
|
return None
|
56
56
|
|
57
|
-
want_opus = fmt in
|
57
|
+
want_opus = fmt in EXTS_AC
|
58
58
|
is_au = ext in self.fmt_ffa
|
59
59
|
is_vau = want_opus and ext in self.fmt_ffv
|
60
60
|
if is_au or is_vau:
|
61
61
|
if want_opus:
|
62
62
|
if self.args.no_acode:
|
63
63
|
return None
|
64
|
+
elif fmt == "caf" and self.args.no_caf:
|
65
|
+
fmt = "mp3"
|
66
|
+
elif fmt == "owa" and self.args.no_owa:
|
67
|
+
fmt = "mp3"
|
64
68
|
else:
|
65
69
|
if "dathumb" in dbv.flags:
|
66
70
|
return None
|