copyparty 1.19.1__py3-none-any.whl → 1.19.3__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 +116 -28
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +33 -7
- copyparty/cfg.py +7 -1
- copyparty/dxml.py +3 -0
- copyparty/ftpd.py +21 -6
- copyparty/httpcli.py +81 -16
- copyparty/httpsrv.py +6 -0
- copyparty/mtag.py +88 -6
- copyparty/svchub.py +76 -5
- copyparty/tcpsrv.py +6 -0
- copyparty/th_cli.py +5 -1
- copyparty/th_srv.py +160 -51
- copyparty/u2idx.py +1 -1
- copyparty/up2k.py +80 -39
- copyparty/util.py +25 -1
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/rups.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +8 -1
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/METADATA +39 -3
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/RECORD +32 -32
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/WHEEL +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/top_level.txt +0 -0
copyparty/httpcli.py
CHANGED
@@ -557,7 +557,7 @@ class HttpCli(object):
|
|
557
557
|
|
558
558
|
zso = self.headers.get("cookie")
|
559
559
|
if zso:
|
560
|
-
if len(zso) >
|
560
|
+
if len(zso) > self.args.cookie_cmax:
|
561
561
|
self.loud_reply("cookie header too big", status=400)
|
562
562
|
return False
|
563
563
|
zsll = [x.split("=", 1) for x in zso.split(";") if "=" in x]
|
@@ -565,11 +565,15 @@ class HttpCli(object):
|
|
565
565
|
cookie_pw = cookies.get("cppws") or cookies.get("cppwd") or ""
|
566
566
|
if "b" in cookies and "b" not in uparam:
|
567
567
|
uparam["b"] = cookies["b"]
|
568
|
+
if len(cookies) > self.args.cookie_nmax:
|
569
|
+
self.loud_reply("too many cookies", status=400)
|
568
570
|
else:
|
569
571
|
cookies = {}
|
570
572
|
cookie_pw = ""
|
571
573
|
|
572
|
-
if len(uparam) >
|
574
|
+
if len(uparam) > 12:
|
575
|
+
t = "http-request rejected; num.params: %d %r"
|
576
|
+
self.log(t % (len(uparam), self.req), 3)
|
573
577
|
self.loud_reply("u wot m8", status=400)
|
574
578
|
return False
|
575
579
|
|
@@ -615,8 +619,22 @@ class HttpCli(object):
|
|
615
619
|
or "*"
|
616
620
|
)
|
617
621
|
|
618
|
-
if self.args.
|
619
|
-
idp_usr =
|
622
|
+
if self.args.have_idp_hdrs:
|
623
|
+
idp_usr = ""
|
624
|
+
if self.args.idp_hm_usr:
|
625
|
+
for hn, hmv in self.args.idp_hm_usr_p.items():
|
626
|
+
zs = self.headers.get(hn)
|
627
|
+
if zs:
|
628
|
+
for zs1, zs2 in hmv.items():
|
629
|
+
if zs == zs1:
|
630
|
+
idp_usr = zs2
|
631
|
+
break
|
632
|
+
if idp_usr:
|
633
|
+
break
|
634
|
+
for hn in self.args.idp_h_usr:
|
635
|
+
if idp_usr:
|
636
|
+
break
|
637
|
+
idp_usr = self.headers.get(hn)
|
620
638
|
if idp_usr:
|
621
639
|
idp_grp = (
|
622
640
|
self.headers.get(self.args.idp_h_grp) or ""
|
@@ -672,8 +690,14 @@ class HttpCli(object):
|
|
672
690
|
else:
|
673
691
|
self.log("unknown username: %r" % (idp_usr,), 1)
|
674
692
|
|
675
|
-
if self.args.
|
676
|
-
self.
|
693
|
+
if self.args.have_ipu_or_ipr:
|
694
|
+
if self.args.ipu and self.uname == "*":
|
695
|
+
self.uname = self.conn.ipu_iu[self.conn.ipu_nm.map(self.ip)]
|
696
|
+
ipr = self.conn.hsrv.ipr
|
697
|
+
if ipr and self.uname in ipr:
|
698
|
+
if not ipr[self.uname].map(self.ip):
|
699
|
+
self.log("username [%s] rejected by --ipr" % (self.uname,), 3)
|
700
|
+
self.uname = "*"
|
677
701
|
|
678
702
|
self.rvol = self.asrv.vfs.aread[self.uname]
|
679
703
|
self.wvol = self.asrv.vfs.awrite[self.uname]
|
@@ -695,7 +719,7 @@ class HttpCli(object):
|
|
695
719
|
cookies["b"] = ""
|
696
720
|
|
697
721
|
vn, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False)
|
698
|
-
if "xdev" in vn.flags or "xvol" in vn.flags:
|
722
|
+
if vn.realpath and ("xdev" in vn.flags or "xvol" in vn.flags):
|
699
723
|
ap = vn.canonical(rem)
|
700
724
|
avn = vn.chk_ap(ap)
|
701
725
|
else:
|
@@ -1979,6 +2003,9 @@ class HttpCli(object):
|
|
1979
2003
|
if "eshare" in self.uparam:
|
1980
2004
|
return self.handle_eshare()
|
1981
2005
|
|
2006
|
+
if "fs_abrt" in self.uparam:
|
2007
|
+
return self.handle_fs_abrt()
|
2008
|
+
|
1982
2009
|
if "application/octet-stream" in ctype:
|
1983
2010
|
return self.handle_post_binary()
|
1984
2011
|
|
@@ -5451,6 +5478,10 @@ class HttpCli(object):
|
|
5451
5478
|
and ("*" in x.axs.uwrite or self.uname in x.axs.uwrite or x == shr_dbv)
|
5452
5479
|
]
|
5453
5480
|
|
5481
|
+
q = ""
|
5482
|
+
qp = (0,)
|
5483
|
+
q_c = -1
|
5484
|
+
|
5454
5485
|
for vol in allvols:
|
5455
5486
|
cur = idx.get_cur(vol)
|
5456
5487
|
if not cur:
|
@@ -5458,9 +5489,23 @@ class HttpCli(object):
|
|
5458
5489
|
|
5459
5490
|
nfk, fk_alg = fk_vols.get(vol) or (0, 0)
|
5460
5491
|
|
5492
|
+
zi = vol.flags["unp_who"]
|
5493
|
+
if q_c != zi:
|
5494
|
+
q_c = zi
|
5495
|
+
q = "select sz, rd, fn, at from up where "
|
5496
|
+
if zi == 1:
|
5497
|
+
q += "ip=? and un=?"
|
5498
|
+
qp = (self.ip, self.uname, lim)
|
5499
|
+
elif zi == 2:
|
5500
|
+
q += "ip=?"
|
5501
|
+
qp = (self.ip, lim)
|
5502
|
+
if zi == 3:
|
5503
|
+
q += "un=?"
|
5504
|
+
qp = (self.uname, lim)
|
5505
|
+
q += " and at>? order by at desc"
|
5506
|
+
|
5461
5507
|
n = 2000
|
5462
|
-
|
5463
|
-
for sz, rd, fn, at in cur.execute(q, (self.ip, lim)):
|
5508
|
+
for sz, rd, fn, at in cur.execute(q, qp):
|
5464
5509
|
vp = "/" + "/".join(x for x in [vol.vpath, rd, fn] if x)
|
5465
5510
|
if nfi == 0 or (nfi == 1 and vfi in vp.lower()):
|
5466
5511
|
pass
|
@@ -5584,8 +5629,8 @@ class HttpCli(object):
|
|
5584
5629
|
continue
|
5585
5630
|
|
5586
5631
|
n = 1000
|
5587
|
-
q = "select sz, rd, fn, ip, at from up where at>0 order by at desc"
|
5588
|
-
for sz, rd, fn, ip, at in cur.execute(q):
|
5632
|
+
q = "select sz, rd, fn, ip, at, un from up where at>0 order by at desc"
|
5633
|
+
for sz, rd, fn, ip, at, un in cur.execute(q):
|
5589
5634
|
vp = "/" + "/".join(x for x in [vol.vpath, rd, fn] if x)
|
5590
5635
|
if nfi == 0 or (nfi == 1 and vfi in vp.lower()):
|
5591
5636
|
pass
|
@@ -5606,6 +5651,7 @@ class HttpCli(object):
|
|
5606
5651
|
"sz": sz,
|
5607
5652
|
"ip": ip,
|
5608
5653
|
"at": at,
|
5654
|
+
"un": un,
|
5609
5655
|
"nfk": nfk,
|
5610
5656
|
"adm": adm,
|
5611
5657
|
}
|
@@ -5650,12 +5696,16 @@ class HttpCli(object):
|
|
5650
5696
|
adm = rv.pop("adm")
|
5651
5697
|
if not adm:
|
5652
5698
|
rv["ip"] = "(You)" if rv["ip"] == self.ip else "(?)"
|
5699
|
+
if rv["un"] not in ("*", self.uname):
|
5700
|
+
rv["un"] = "(?)"
|
5653
5701
|
else:
|
5654
5702
|
for rv in ret:
|
5655
5703
|
adm = rv.pop("adm")
|
5656
5704
|
if not adm:
|
5657
5705
|
rv["ip"] = "(You)" if rv["ip"] == self.ip else "(?)"
|
5658
5706
|
rv["at"] = 0
|
5707
|
+
if rv["un"] not in ("*", self.uname):
|
5708
|
+
rv["un"] = "(?)"
|
5659
5709
|
|
5660
5710
|
if self.is_vproxied:
|
5661
5711
|
for v in ret:
|
@@ -5934,7 +5984,9 @@ class HttpCli(object):
|
|
5934
5984
|
self.asrv.vfs.get(vdst, self.uname, False, True, False, True)
|
5935
5985
|
wunlink(self.log, dabs, dvn.flags)
|
5936
5986
|
|
5937
|
-
x = self.conn.hsrv.broker.ask(
|
5987
|
+
x = self.conn.hsrv.broker.ask(
|
5988
|
+
"up2k.handle_mv", self.ouparam.get("akey"), self.uname, self.ip, vsrc, vdst
|
5989
|
+
)
|
5938
5990
|
self.loud_reply(x.get(), status=201)
|
5939
5991
|
return True
|
5940
5992
|
|
@@ -5964,10 +6016,21 @@ class HttpCli(object):
|
|
5964
6016
|
self.asrv.vfs.get(vdst, self.uname, False, True, False, True)
|
5965
6017
|
wunlink(self.log, dabs, dvn.flags)
|
5966
6018
|
|
5967
|
-
x = self.conn.hsrv.broker.ask(
|
6019
|
+
x = self.conn.hsrv.broker.ask(
|
6020
|
+
"up2k.handle_cp", self.ouparam.get("akey"), self.uname, self.ip, vsrc, vdst
|
6021
|
+
)
|
5968
6022
|
self.loud_reply(x.get(), status=201)
|
5969
6023
|
return True
|
5970
6024
|
|
6025
|
+
def handle_fs_abrt(self):
|
6026
|
+
if self.args.no_fs_abrt:
|
6027
|
+
t = "aborting an ongoing copy/move is disabled in server config"
|
6028
|
+
raise Pebkac(403, t)
|
6029
|
+
|
6030
|
+
self.conn.hsrv.broker.say("up2k.handle_fs_abrt", self.uparam["fs_abrt"])
|
6031
|
+
self.loud_reply("aborting", status=200)
|
6032
|
+
return True
|
6033
|
+
|
5971
6034
|
def tx_ls(self, ls ) :
|
5972
6035
|
dirs = ls["dirs"]
|
5973
6036
|
files = ls["files"]
|
@@ -6563,13 +6626,15 @@ class HttpCli(object):
|
|
6563
6626
|
tags = {k: v for k, v in r}
|
6564
6627
|
|
6565
6628
|
if is_admin:
|
6566
|
-
q = "select ip, at from up where rd=? and fn=?"
|
6629
|
+
q = "select ip, at, un from up where rd=? and fn=?"
|
6567
6630
|
try:
|
6568
|
-
zs1, zs2 = icur.execute(q, erd_efn).fetchone()
|
6631
|
+
zs1, zs2, zs3 = icur.execute(q, erd_efn).fetchone()
|
6569
6632
|
if zs1:
|
6570
6633
|
tags["up_ip"] = zs1
|
6571
6634
|
if zs2:
|
6572
6635
|
tags[".up_at"] = zs2
|
6636
|
+
if zs3:
|
6637
|
+
tags["up_by"] = zs3
|
6573
6638
|
except:
|
6574
6639
|
pass
|
6575
6640
|
elif add_up_at:
|
@@ -6590,7 +6655,7 @@ class HttpCli(object):
|
|
6590
6655
|
|
6591
6656
|
lmte = list(mte)
|
6592
6657
|
if self.can_admin:
|
6593
|
-
lmte.extend(("up_ip", ".up_at"))
|
6658
|
+
lmte.extend(("up_by", "up_ip", ".up_at"))
|
6594
6659
|
|
6595
6660
|
if "nodirsz" not in vf:
|
6596
6661
|
tagset.add(".files")
|
copyparty/httpsrv.py
CHANGED
@@ -70,6 +70,7 @@ from .util import (
|
|
70
70
|
build_netmap,
|
71
71
|
has_resource,
|
72
72
|
ipnorm,
|
73
|
+
load_ipr,
|
73
74
|
load_ipu,
|
74
75
|
load_resource,
|
75
76
|
min_ex,
|
@@ -189,6 +190,11 @@ class HttpSrv(object):
|
|
189
190
|
else:
|
190
191
|
self.ipu_iu = self.ipu_nm = None
|
191
192
|
|
193
|
+
if self.args.ipr:
|
194
|
+
self.ipr = load_ipr(self.log, self.args.ipr)
|
195
|
+
else:
|
196
|
+
self.ipr = None
|
197
|
+
|
192
198
|
self.ipa_nm = build_netmap(self.args.ipa)
|
193
199
|
self.xff_nm = build_netmap(self.args.xff_src)
|
194
200
|
self.xff_lan = build_netmap("lan")
|
copyparty/mtag.py
CHANGED
@@ -170,6 +170,9 @@ def au_unpk(
|
|
170
170
|
raise Exception("no images inside cbz")
|
171
171
|
fi = zf.open(using)
|
172
172
|
|
173
|
+
elif pk == "epub":
|
174
|
+
fi = get_cover_from_epub(log, abspath)
|
175
|
+
|
173
176
|
else:
|
174
177
|
raise Exception("unknown compression %s" % (pk,))
|
175
178
|
|
@@ -199,7 +202,7 @@ def au_unpk(
|
|
199
202
|
|
200
203
|
def ffprobe(
|
201
204
|
abspath , timeout = 60
|
202
|
-
)
|
205
|
+
) :
|
203
206
|
cmd = [
|
204
207
|
b"ffprobe",
|
205
208
|
b"-hide_banner",
|
@@ -213,8 +216,17 @@ def ffprobe(
|
|
213
216
|
return parse_ffprobe(so)
|
214
217
|
|
215
218
|
|
216
|
-
def parse_ffprobe(
|
217
|
-
|
219
|
+
def parse_ffprobe(
|
220
|
+
txt ,
|
221
|
+
) :
|
222
|
+
"""
|
223
|
+
txt: output from ffprobe -show_format -show_streams
|
224
|
+
returns:
|
225
|
+
* normalized tags
|
226
|
+
* original/raw tags
|
227
|
+
* list of streams
|
228
|
+
* format props
|
229
|
+
"""
|
218
230
|
streams = []
|
219
231
|
fmt = {}
|
220
232
|
g = {}
|
@@ -307,7 +319,7 @@ def parse_ffprobe(txt ) :
|
|
307
319
|
ret[rk] = v1
|
308
320
|
|
309
321
|
if ret.get("vc") == "ansi": # shellscript
|
310
|
-
return {}, {}
|
322
|
+
return {}, {}, [], {}
|
311
323
|
|
312
324
|
for strm in streams:
|
313
325
|
for sk, sv in strm.items():
|
@@ -356,7 +368,77 @@ def parse_ffprobe(txt ) :
|
|
356
368
|
zero = int("0")
|
357
369
|
zd = {k: (zero, v) for k, v in ret.items()}
|
358
370
|
|
359
|
-
return zd, md
|
371
|
+
return zd, md, streams, fmt
|
372
|
+
|
373
|
+
|
374
|
+
def get_cover_from_epub(log , abspath ) :
|
375
|
+
import zipfile
|
376
|
+
|
377
|
+
from .dxml import parse_xml
|
378
|
+
|
379
|
+
try:
|
380
|
+
from urlparse import urljoin # Python2
|
381
|
+
except ImportError:
|
382
|
+
from urllib.parse import urljoin # Python3
|
383
|
+
|
384
|
+
with zipfile.ZipFile(abspath, "r") as z:
|
385
|
+
# First open the container file to find the package document (.opf file)
|
386
|
+
try:
|
387
|
+
container_root = parse_xml(z.read("META-INF/container.xml").decode())
|
388
|
+
except KeyError:
|
389
|
+
log("epub: no container file found in %s" % (abspath,))
|
390
|
+
return None
|
391
|
+
|
392
|
+
# https://www.w3.org/TR/epub-33/#sec-container.xml-rootfile-elem
|
393
|
+
container_ns = {"": "urn:oasis:names:tc:opendocument:xmlns:container"}
|
394
|
+
# One file could contain multiple package documents, default to the first one
|
395
|
+
rootfile_path = container_root.find("./rootfiles/rootfile", container_ns).get(
|
396
|
+
"full-path"
|
397
|
+
)
|
398
|
+
|
399
|
+
# Then open the first package document to find the path of the cover image
|
400
|
+
try:
|
401
|
+
package_root = parse_xml(z.read(rootfile_path).decode())
|
402
|
+
except KeyError:
|
403
|
+
log("epub: no package document found in %s" % (abspath,))
|
404
|
+
return None
|
405
|
+
|
406
|
+
# https://www.w3.org/TR/epub-33/#sec-package-doc
|
407
|
+
package_ns = {"": "http://www.idpf.org/2007/opf"}
|
408
|
+
# https://www.w3.org/TR/epub-33/#sec-cover-image
|
409
|
+
coverimage_path_node = package_root.find(
|
410
|
+
"./manifest/item[@properties='cover-image']", package_ns
|
411
|
+
)
|
412
|
+
if coverimage_path_node is not None:
|
413
|
+
coverimage_path = coverimage_path_node.get("href")
|
414
|
+
else:
|
415
|
+
# This might be an EPUB2 file, try the legacy way of specifying covers
|
416
|
+
coverimage_path = _get_cover_from_epub2(log, package_root, package_ns)
|
417
|
+
|
418
|
+
# This url is either absolute (in the .epub) or relative to the package document
|
419
|
+
adjusted_cover_path = urljoin(rootfile_path, coverimage_path)
|
420
|
+
|
421
|
+
return z.open(adjusted_cover_path)
|
422
|
+
|
423
|
+
|
424
|
+
def _get_cover_from_epub2(
|
425
|
+
log , package_root, package_ns
|
426
|
+
) :
|
427
|
+
# <meta name="cover" content="id-to-cover-image"> in <metadata>, then
|
428
|
+
# <item> in <manifest>
|
429
|
+
cover_id = package_root.find("./metadata/meta[@name='cover']", package_ns).get(
|
430
|
+
"content"
|
431
|
+
)
|
432
|
+
|
433
|
+
if not cover_id:
|
434
|
+
return None
|
435
|
+
|
436
|
+
for node in package_root.iterfind("./manifest/item", package_ns):
|
437
|
+
if node.get("id") == cover_id:
|
438
|
+
cover_path = node.get("href")
|
439
|
+
return cover_path
|
440
|
+
|
441
|
+
return None
|
360
442
|
|
361
443
|
|
362
444
|
class MTag(object):
|
@@ -627,7 +709,7 @@ class MTag(object):
|
|
627
709
|
if not bos.path.isfile(abspath):
|
628
710
|
return {}
|
629
711
|
|
630
|
-
ret, md = ffprobe(abspath, self.args.mtag_to)
|
712
|
+
ret, md, _, _ = ffprobe(abspath, self.args.mtag_to)
|
631
713
|
|
632
714
|
if self.args.mtag_vv:
|
633
715
|
for zd in (ret, dict(md)):
|
copyparty/svchub.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
4
|
import argparse
|
5
|
+
import atexit
|
5
6
|
import errno
|
6
7
|
import logging
|
7
8
|
import os
|
@@ -32,6 +33,7 @@ from .th_srv import (
|
|
32
33
|
HAVE_FFPROBE,
|
33
34
|
HAVE_HEIF,
|
34
35
|
HAVE_PIL,
|
36
|
+
HAVE_RAW,
|
35
37
|
HAVE_VIPS,
|
36
38
|
HAVE_WEBP,
|
37
39
|
ThumbSrv,
|
@@ -58,6 +60,7 @@ from .util import (
|
|
58
60
|
build_netmap,
|
59
61
|
expat_ver,
|
60
62
|
gzip,
|
63
|
+
load_ipr,
|
61
64
|
load_ipu,
|
62
65
|
lock_file,
|
63
66
|
min_ex,
|
@@ -66,6 +69,7 @@ from .util import (
|
|
66
69
|
pybin,
|
67
70
|
start_log_thrs,
|
68
71
|
start_stackmon,
|
72
|
+
termsize,
|
69
73
|
ub64enc,
|
70
74
|
)
|
71
75
|
|
@@ -146,6 +150,7 @@ class SvcHub(object):
|
|
146
150
|
args.no_del = True
|
147
151
|
args.no_mv = True
|
148
152
|
args.hardlink = True
|
153
|
+
args.dav_auth = True
|
149
154
|
args.vague_403 = True
|
150
155
|
args.nih = True
|
151
156
|
|
@@ -234,7 +239,7 @@ class SvcHub(object):
|
|
234
239
|
t = "WARNING: --th-ram-max is very small (%.2f GiB); will not be able to %s"
|
235
240
|
self.log("root", t % (args.th_ram_max, zs), 3)
|
236
241
|
|
237
|
-
if args.chpw and args.
|
242
|
+
if args.chpw and args.have_idp_hdrs:
|
238
243
|
t = "ERROR: user-changeable passwords is incompatible with IdP/identity-providers; you must disable either --chpw or --idp-h-usr"
|
239
244
|
self.log("root", t, 1)
|
240
245
|
raise Exception(t)
|
@@ -250,6 +255,10 @@ class SvcHub(object):
|
|
250
255
|
setattr(args, "ipu_iu", iu)
|
251
256
|
setattr(args, "ipu_nm", nm)
|
252
257
|
|
258
|
+
if args.ipr:
|
259
|
+
ipr = load_ipr(self.log, args.ipr, True)
|
260
|
+
setattr(args, "ipr_u", ipr)
|
261
|
+
|
253
262
|
for zs in "ah_salt fk_salt dk_salt".split():
|
254
263
|
if getattr(args, "show_%s" % (zs,)):
|
255
264
|
self.log("root", "effective %s is %s" % (zs, getattr(args, zs)))
|
@@ -259,7 +268,7 @@ class SvcHub(object):
|
|
259
268
|
args.no_ses = True
|
260
269
|
args.shr = ""
|
261
270
|
|
262
|
-
if args.idp_store and args.
|
271
|
+
if args.idp_store and args.have_idp_hdrs:
|
263
272
|
self.setup_db("idp")
|
264
273
|
|
265
274
|
if not self.args.no_ses:
|
@@ -315,6 +324,8 @@ class SvcHub(object):
|
|
315
324
|
decs.pop("vips", None)
|
316
325
|
if not HAVE_PIL:
|
317
326
|
decs.pop("pil", None)
|
327
|
+
if not HAVE_RAW:
|
328
|
+
decs.pop("raw", None)
|
318
329
|
if not HAVE_FFMPEG or not HAVE_FFPROBE:
|
319
330
|
decs.pop("ff", None)
|
320
331
|
|
@@ -421,6 +432,9 @@ class SvcHub(object):
|
|
421
432
|
getattr(args, zs).mutex = threading.Lock()
|
422
433
|
except:
|
423
434
|
pass
|
435
|
+
if args.ipr:
|
436
|
+
for nm in args.ipr_u.values():
|
437
|
+
nm.mutex = threading.Lock()
|
424
438
|
|
425
439
|
def _db_onfail_ses(self) :
|
426
440
|
self.args.no_ses = True
|
@@ -762,6 +776,39 @@ class SvcHub(object):
|
|
762
776
|
def sigterm(self) :
|
763
777
|
self.signal_handler(signal.SIGTERM, None)
|
764
778
|
|
779
|
+
def sticky_qr(self) :
|
780
|
+
tw, th = termsize()
|
781
|
+
zs1, qr = self.tcpsrv.qr.split("\n", 1)
|
782
|
+
url, colr = zs1.split(" ", 1)
|
783
|
+
nl = len(qr.split("\n")) # numlines
|
784
|
+
lp = 3 if nl * 2 + 4 < tw else 0 # leftpad
|
785
|
+
lp0 = lp
|
786
|
+
if self.args.qr_pin == 2:
|
787
|
+
url = ""
|
788
|
+
else:
|
789
|
+
while lp and (nl + lp) * 2 + len(url) + 1 > tw:
|
790
|
+
lp -= 1
|
791
|
+
if (nl + lp) * 2 + len(url) + 1 > tw:
|
792
|
+
qr = url + "\n" + qr
|
793
|
+
url = ""
|
794
|
+
nl += 1
|
795
|
+
lp = lp0
|
796
|
+
sh = 1 + th - nl
|
797
|
+
if lp:
|
798
|
+
zs = " " * lp
|
799
|
+
qr = zs + qr.replace("\n", "\n" + zs)
|
800
|
+
if url:
|
801
|
+
url = "%s\033[%d;%dH%s\033[0m" % (colr, sh + 1, (nl + lp) * 2, url)
|
802
|
+
qr = colr + qr
|
803
|
+
|
804
|
+
def unlock():
|
805
|
+
print("\033[s\033[r\033[u", file=sys.stderr)
|
806
|
+
|
807
|
+
atexit.register(unlock)
|
808
|
+
t = "%s\033[%dA" % ("\n" * nl, nl)
|
809
|
+
t = "%s\033[s\033[1;%dr\033[%dH%s%s\033[u" % (t, sh - 1, sh, qr, url)
|
810
|
+
self.pr(t, file=sys.stderr)
|
811
|
+
|
765
812
|
def cb_httpsrv_up(self) :
|
766
813
|
self.httpsrv_up += 1
|
767
814
|
if self.httpsrv_up != self.broker.num_workers:
|
@@ -774,7 +821,10 @@ class SvcHub(object):
|
|
774
821
|
break
|
775
822
|
|
776
823
|
if self.tcpsrv.qr:
|
777
|
-
|
824
|
+
if self.args.qr_pin:
|
825
|
+
self.sticky_qr()
|
826
|
+
else:
|
827
|
+
self.log("qr-code", self.tcpsrv.qr)
|
778
828
|
else:
|
779
829
|
self.log("root", "workers OK\n")
|
780
830
|
|
@@ -801,6 +851,7 @@ class SvcHub(object):
|
|
801
851
|
(HAVE_ZMQ, "pyzmq", "send zeromq messages from event-hooks"),
|
802
852
|
(HAVE_HEIF, "pillow-heif", "read .heif images with pillow (rarely useful)"),
|
803
853
|
(HAVE_AVIF, "pillow-avif", "read .avif images with pillow (rarely useful)"),
|
854
|
+
(HAVE_RAW, "rawpy", "read RAW images"),
|
804
855
|
]
|
805
856
|
if ANYWIN:
|
806
857
|
to_check += [
|
@@ -959,10 +1010,23 @@ class SvcHub(object):
|
|
959
1010
|
al.sus_urls = None
|
960
1011
|
|
961
1012
|
al.xff_hdr = al.xff_hdr.lower()
|
962
|
-
al.idp_h_usr =
|
1013
|
+
al.idp_h_usr = [x.lower() for x in al.idp_h_usr or []]
|
963
1014
|
al.idp_h_grp = al.idp_h_grp.lower()
|
964
1015
|
al.idp_h_key = al.idp_h_key.lower()
|
965
1016
|
|
1017
|
+
al.idp_hm_usr_p = {}
|
1018
|
+
for zs0 in al.idp_hm_usr or []:
|
1019
|
+
try:
|
1020
|
+
sep = zs0[:1]
|
1021
|
+
hn, zs1, zs2 = zs0[1:].split(sep)
|
1022
|
+
hn = hn.lower()
|
1023
|
+
if hn in al.idp_hm_usr_p:
|
1024
|
+
al.idp_hm_usr_p[hn][zs1] = zs2
|
1025
|
+
else:
|
1026
|
+
al.idp_hm_usr_p[hn] = {zs1: zs2}
|
1027
|
+
except:
|
1028
|
+
raise Exception("invalid --idp-hm-usr [%s]" % (zs0,))
|
1029
|
+
|
966
1030
|
al.ftp_ipa_nm = build_netmap(al.ftp_ipa or al.ipa, True)
|
967
1031
|
al.tftp_ipa_nm = build_netmap(al.tftp_ipa or al.ipa, True)
|
968
1032
|
|
@@ -1390,7 +1454,14 @@ class SvcHub(object):
|
|
1390
1454
|
|
1391
1455
|
fmt = "\033[36m%s \033[33m%-21s \033[0m%s\n"
|
1392
1456
|
if self.no_ansi:
|
1393
|
-
|
1457
|
+
if c == 1:
|
1458
|
+
fmt = "%s %-21s CRIT: %s\n"
|
1459
|
+
elif c == 3:
|
1460
|
+
fmt = "%s %-21s WARN: %s\n"
|
1461
|
+
elif c == 6:
|
1462
|
+
fmt = "%s %-21s BTW: %s\n"
|
1463
|
+
else:
|
1464
|
+
fmt = "%s %-21s LOG: %s\n"
|
1394
1465
|
if "\033" in msg:
|
1395
1466
|
msg = RE_ANSI.sub("", msg)
|
1396
1467
|
if "\033" in src:
|
copyparty/tcpsrv.py
CHANGED
@@ -611,6 +611,10 @@ class TcpSrv(object):
|
|
611
611
|
|
612
612
|
fg = self.args.qr_fg
|
613
613
|
bg = self.args.qr_bg
|
614
|
+
nocolor = fg == -1
|
615
|
+
if nocolor:
|
616
|
+
fg = 0
|
617
|
+
|
614
618
|
pad = self.args.qrp
|
615
619
|
zoom = self.args.qrz
|
616
620
|
qrc = QrCode.encode_binary(btxt)
|
@@ -638,6 +642,8 @@ class TcpSrv(object):
|
|
638
642
|
|
639
643
|
qr = qr.replace("\n", "\033[K\n") + "\033[K" # win10do
|
640
644
|
cc = " \033[0;38;5;{0};47;48;5;{1}m" if fg else " \033[0;30;47m"
|
645
|
+
if nocolor:
|
646
|
+
cc = " \033[0m"
|
641
647
|
t = cc + "\n{2}\033[999G\033[0m\033[J"
|
642
648
|
t = t.format(fg, bg, qr)
|
643
649
|
if ANYWIN:
|
copyparty/th_cli.py
CHANGED
@@ -33,11 +33,15 @@ class ThumbCli(object):
|
|
33
33
|
if not c:
|
34
34
|
raise Exception()
|
35
35
|
except:
|
36
|
-
c = {
|
36
|
+
c = {
|
37
|
+
k: set()
|
38
|
+
for k in ["thumbable", "pil", "vips", "raw", "ffi", "ffv", "ffa"]
|
39
|
+
}
|
37
40
|
|
38
41
|
self.thumbable = c["thumbable"]
|
39
42
|
self.fmt_pil = c["pil"]
|
40
43
|
self.fmt_vips = c["vips"]
|
44
|
+
self.fmt_raw = c["raw"]
|
41
45
|
self.fmt_ffi = c["ffi"]
|
42
46
|
self.fmt_ffv = c["ffv"]
|
43
47
|
self.fmt_ffa = c["ffa"]
|