copyparty 1.16.8__py3-none-any.whl → 1.16.9__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 +15 -8
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +8 -1
- copyparty/cfg.py +5 -0
- copyparty/dxml.py +48 -3
- copyparty/httpcli.py +23 -8
- copyparty/svchub.py +13 -0
- copyparty/up2k.py +11 -5
- copyparty/util.py +154 -8
- copyparty/web/a/u2c.py +3 -3
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.dist-info}/METADATA +35 -10
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.dist-info}/RECORD +18 -18
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.dist-info}/LICENSE +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.dist-info}/WHEEL +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.dist-info}/entry_points.txt +0 -0
- {copyparty-1.16.8.dist-info → copyparty-1.16.9.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
|
@@ -1468,12 +1473,14 @@ def add_ui(ap, retry):
|
|
1468
1473
|
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
1474
|
ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
|
1470
1475
|
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=
|
1476
|
+
ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-np\033[0m")
|
1472
1477
|
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
|
1473
1478
|
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
1479
|
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
|
1480
|
+
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")
|
1481
|
+
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)")
|
1482
|
+
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)")
|
1483
|
+
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
1484
|
ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
|
1478
1485
|
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
1486
|
|
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",
|
@@ -144,6 +146,7 @@ flagcats = {
|
|
144
146
|
"noclone": "take dupe data from clients, even if available on HDD",
|
145
147
|
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
146
148
|
"sparse": "force use of sparse files, mainly for s3-backed storage",
|
149
|
+
"nosparse": "deny use of sparse files, mainly for slow storage",
|
147
150
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
148
151
|
"nosub": "forces all uploads into the top folder of the vfs",
|
149
152
|
"magic": "enables filetype detection for nameless uploads",
|
@@ -240,6 +243,8 @@ flagcats = {
|
|
240
243
|
"sb_lg": "enable js sandbox for prologue/epilogue (default)",
|
241
244
|
"md_sbf": "list of markdown-sandbox safeguards to disable",
|
242
245
|
"lg_sbf": "list of *logue-sandbox safeguards to disable",
|
246
|
+
"md_sba": "value of iframe allow-prop for markdown-sandbox",
|
247
|
+
"lg_sba": "value of iframe allow-prop for *logue-sandbox",
|
243
248
|
"nohtml": "return html and markdown as text/html",
|
244
249
|
},
|
245
250
|
"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"
|
@@ -4334,7 +4337,7 @@ class HttpCli(object):
|
|
4334
4337
|
self.log,
|
4335
4338
|
self.asrv,
|
4336
4339
|
fgen,
|
4337
|
-
utf8="utf" in uarg,
|
4340
|
+
utf8="utf" in uarg or not uarg,
|
4338
4341
|
pre_crc="crc" in uarg,
|
4339
4342
|
cmp=uarg if cancmp or uarg == "pax" else "",
|
4340
4343
|
)
|
@@ -4982,8 +4985,16 @@ class HttpCli(object):
|
|
4982
4985
|
and (self.uname in vol.axs.uread or self.uname in vol.axs.upget)
|
4983
4986
|
}
|
4984
4987
|
|
4988
|
+
bad_xff = hasattr(self, "bad_xff")
|
4989
|
+
if bad_xff:
|
4990
|
+
allvols = []
|
4991
|
+
t = "will not return list of recent uploads" + BADXFF
|
4992
|
+
self.log(t, 1)
|
4993
|
+
if self.avol:
|
4994
|
+
raise Pebkac(500, t)
|
4995
|
+
|
4985
4996
|
x = self.conn.hsrv.broker.ask(
|
4986
|
-
"up2k.get_unfinished_by_user", self.uname, self.ip
|
4997
|
+
"up2k.get_unfinished_by_user", self.uname, "" if bad_xff else self.ip
|
4987
4998
|
)
|
4988
4999
|
uret = x.get()
|
4989
5000
|
|
@@ -5377,12 +5388,16 @@ class HttpCli(object):
|
|
5377
5388
|
if self.args.no_del:
|
5378
5389
|
raise Pebkac(403, "the delete feature is disabled in server config")
|
5379
5390
|
|
5391
|
+
unpost = "unpost" in self.uparam
|
5392
|
+
if unpost and hasattr(self, "bad_xff"):
|
5393
|
+
self.log("unpost was denied" + BADXFF, 1)
|
5394
|
+
raise Pebkac(403, "the delete feature is disabled in server config")
|
5395
|
+
|
5380
5396
|
if not req:
|
5381
5397
|
req = [self.vpath]
|
5382
5398
|
elif self.is_vproxied:
|
5383
5399
|
req = [x[len(self.args.SR) :] for x in req]
|
5384
5400
|
|
5385
|
-
unpost = "unpost" in self.uparam
|
5386
5401
|
nlim = int(self.uparam.get("lim") or 0)
|
5387
5402
|
lim = [nlim, nlim] if nlim else []
|
5388
5403
|
|
@@ -5782,7 +5797,7 @@ class HttpCli(object):
|
|
5782
5797
|
"taglist": [],
|
5783
5798
|
"have_tags_idx": int(e2t),
|
5784
5799
|
"have_b_u": (self.can_write and self.uparam.get("b") == "u"),
|
5785
|
-
"sb_lg":
|
5800
|
+
"sb_lg": vn.js_ls["sb_lg"],
|
5786
5801
|
"url_suf": url_suf,
|
5787
5802
|
"title": html_escape("%s %s" % (self.args.bname, self.vpath), crlf=True),
|
5788
5803
|
"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/up2k.py
CHANGED
@@ -790,7 +790,7 @@ class Up2k(object):
|
|
790
790
|
continue
|
791
791
|
|
792
792
|
self.log("xiu: %d# %r" % (len(wrfs), cmd))
|
793
|
-
runihook(self.log, cmd, vol, ups)
|
793
|
+
runihook(self.log, self.args.hook_v, cmd, vol, ups)
|
794
794
|
|
795
795
|
def _vis_job_progress(self, job ) :
|
796
796
|
perc = 100 - (len(job["need"]) * 100.0 / (len(job["hash"]) or 1))
|
@@ -4881,7 +4881,8 @@ class Up2k(object):
|
|
4881
4881
|
except:
|
4882
4882
|
pass
|
4883
4883
|
|
4884
|
-
|
4884
|
+
vf = self.flags[job["ptop"]]
|
4885
|
+
xbu = vf.get("xbu")
|
4885
4886
|
ap_chk = djoin(pdir, job["name"])
|
4886
4887
|
vp_chk = djoin(job["vtop"], job["prel"], job["name"])
|
4887
4888
|
if xbu:
|
@@ -4911,7 +4912,7 @@ class Up2k(object):
|
|
4911
4912
|
if x:
|
4912
4913
|
zvfs = vfs
|
4913
4914
|
pdir, _, job["name"], (vfs, rem) = x
|
4914
|
-
job["vcfg"] = vfs.flags
|
4915
|
+
job["vcfg"] = vf = vfs.flags
|
4915
4916
|
job["ptop"] = vfs.realpath
|
4916
4917
|
job["vtop"] = vfs.vpath
|
4917
4918
|
job["prel"] = rem
|
@@ -4961,8 +4962,13 @@ class Up2k(object):
|
|
4961
4962
|
fs = self.fstab.get(pdir)
|
4962
4963
|
if fs == "ok":
|
4963
4964
|
pass
|
4964
|
-
elif "
|
4965
|
-
t = "volflag '
|
4965
|
+
elif "nosparse" in vf:
|
4966
|
+
t = "volflag 'nosparse' is preventing creation of sparse files for uploads to [%s]"
|
4967
|
+
self.log(t % (job["ptop"],))
|
4968
|
+
relabel = True
|
4969
|
+
sprs = False
|
4970
|
+
elif "sparse" in vf:
|
4971
|
+
t = "volflag 'sparse' is forcing creation of sparse files for uploads to [%s]"
|
4966
4972
|
self.log(t % (job["ptop"],))
|
4967
4973
|
relabel = True
|
4968
4974
|
else:
|
copyparty/util.py
CHANGED
@@ -120,6 +120,13 @@ try:
|
|
120
120
|
except:
|
121
121
|
HAVE_SQLITE3 = False
|
122
122
|
|
123
|
+
try:
|
124
|
+
import importlib.util
|
125
|
+
|
126
|
+
HAVE_ZMQ = bool(importlib.util.find_spec("zmq"))
|
127
|
+
except:
|
128
|
+
HAVE_ZMQ = False
|
129
|
+
|
123
130
|
try:
|
124
131
|
if os.environ.get("PRTY_NO_PSUTIL"):
|
125
132
|
raise Exception()
|
@@ -208,6 +215,10 @@ META_NOBOTS = '<meta name="robots" content="noindex, nofollow">\n'
|
|
208
215
|
|
209
216
|
FFMPEG_URL = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
|
210
217
|
|
218
|
+
URL_PRJ = "https://github.com/9001/copyparty"
|
219
|
+
|
220
|
+
URL_BUG = URL_PRJ + "/issues/new?labels=bug&template=bug_report.md"
|
221
|
+
|
211
222
|
HTTPCODE = {
|
212
223
|
200: "OK",
|
213
224
|
201: "Created",
|
@@ -470,6 +481,15 @@ def py_desc() :
|
|
470
481
|
)
|
471
482
|
|
472
483
|
|
484
|
+
def expat_ver() :
|
485
|
+
try:
|
486
|
+
import pyexpat
|
487
|
+
|
488
|
+
return ".".join([str(x) for x in pyexpat.version_info])
|
489
|
+
except:
|
490
|
+
return "?"
|
491
|
+
|
492
|
+
|
473
493
|
def _sqlite_ver() :
|
474
494
|
try:
|
475
495
|
co = sqlite3.connect(":memory:")
|
@@ -3297,6 +3317,7 @@ def _parsehook(
|
|
3297
3317
|
|
3298
3318
|
def runihook(
|
3299
3319
|
log ,
|
3320
|
+
verbose ,
|
3300
3321
|
cmd ,
|
3301
3322
|
vol ,
|
3302
3323
|
ups ,
|
@@ -3326,6 +3347,17 @@ def runihook(
|
|
3326
3347
|
else:
|
3327
3348
|
sp_ka["sin"] = b"\n".join(fsenc(x) for x in aps)
|
3328
3349
|
|
3350
|
+
if acmd[0].startswith("zmq:"):
|
3351
|
+
try:
|
3352
|
+
msg = sp_ka["sin"].decode("utf-8", "replace")
|
3353
|
+
_zmq_hook(log, verbose, "xiu", acmd[0][4:].lower(), msg, wait, sp_ka)
|
3354
|
+
if verbose and log:
|
3355
|
+
log("hook(xiu) %r OK" % (cmd,), 6)
|
3356
|
+
except Exception as ex:
|
3357
|
+
if log:
|
3358
|
+
log("zeromq failed: %r" % (ex,))
|
3359
|
+
return True
|
3360
|
+
|
3329
3361
|
t0 = time.time()
|
3330
3362
|
if fork:
|
3331
3363
|
Daemon(runcmd, cmd, bcmd, ka=sp_ka)
|
@@ -3335,15 +3367,118 @@ def runihook(
|
|
3335
3367
|
retchk(rc, bcmd, err, log, 5)
|
3336
3368
|
return False
|
3337
3369
|
|
3338
|
-
wait
|
3339
|
-
|
3340
|
-
|
3370
|
+
if wait:
|
3371
|
+
wait -= time.time() - t0
|
3372
|
+
if wait > 0:
|
3373
|
+
time.sleep(wait)
|
3341
3374
|
|
3342
3375
|
return True
|
3343
3376
|
|
3344
3377
|
|
3378
|
+
ZMQ = {}
|
3379
|
+
ZMQ_DESC = {
|
3380
|
+
"pub": "fire-and-forget to all/any connected SUB-clients",
|
3381
|
+
"push": "fire-and-forget to one of the connected PULL-clients",
|
3382
|
+
"req": "send messages to a REP-server and blocking-wait for ack",
|
3383
|
+
}
|
3384
|
+
|
3385
|
+
|
3386
|
+
def _zmq_hook(
|
3387
|
+
log ,
|
3388
|
+
verbose ,
|
3389
|
+
src ,
|
3390
|
+
cmd ,
|
3391
|
+
msg ,
|
3392
|
+
wait ,
|
3393
|
+
sp_ka ,
|
3394
|
+
) :
|
3395
|
+
import zmq
|
3396
|
+
|
3397
|
+
try:
|
3398
|
+
mtx = ZMQ["mtx"]
|
3399
|
+
except:
|
3400
|
+
ZMQ["mtx"] = threading.Lock()
|
3401
|
+
time.sleep(0.1)
|
3402
|
+
mtx = ZMQ["mtx"]
|
3403
|
+
|
3404
|
+
ret = ""
|
3405
|
+
t0 = time.time()
|
3406
|
+
if verbose and log:
|
3407
|
+
log("hook(%s) %r entering zmq-main-lock" % (src, cmd), 6)
|
3408
|
+
|
3409
|
+
with mtx:
|
3410
|
+
try:
|
3411
|
+
mode, sck, mtx = ZMQ[cmd]
|
3412
|
+
except:
|
3413
|
+
mode, uri = cmd.split(":", 1)
|
3414
|
+
try:
|
3415
|
+
desc = ZMQ_DESC[mode]
|
3416
|
+
if log:
|
3417
|
+
t = "libzmq(%s) pyzmq(%s) init(%s); %s"
|
3418
|
+
log(t % (zmq.zmq_version(), zmq.__version__, cmd, desc))
|
3419
|
+
except:
|
3420
|
+
raise Exception("the only supported ZMQ modes are REQ PUB PUSH")
|
3421
|
+
|
3422
|
+
try:
|
3423
|
+
ctx = ZMQ["ctx"]
|
3424
|
+
except:
|
3425
|
+
ctx = ZMQ["ctx"] = zmq.Context()
|
3426
|
+
|
3427
|
+
timeout = sp_ka["timeout"]
|
3428
|
+
|
3429
|
+
if mode == "pub":
|
3430
|
+
sck = ctx.socket(zmq.PUB)
|
3431
|
+
sck.bind(uri)
|
3432
|
+
time.sleep(1) # give clients time to connect; avoids losing first msg
|
3433
|
+
elif mode == "push":
|
3434
|
+
sck = ctx.socket(zmq.PUSH)
|
3435
|
+
sck.bind(uri)
|
3436
|
+
if timeout:
|
3437
|
+
sck.SNDTIMEO = int(timeout * 1000)
|
3438
|
+
elif mode == "req":
|
3439
|
+
sck = ctx.socket(zmq.REQ)
|
3440
|
+
sck.connect(uri)
|
3441
|
+
if timeout:
|
3442
|
+
sck.RCVTIMEO = int(timeout * 1000)
|
3443
|
+
else:
|
3444
|
+
raise Exception()
|
3445
|
+
|
3446
|
+
mtx = threading.Lock()
|
3447
|
+
ZMQ[cmd] = (mode, sck, mtx)
|
3448
|
+
|
3449
|
+
if verbose and log:
|
3450
|
+
log("hook(%s) %r entering socket-lock" % (src, cmd), 6)
|
3451
|
+
|
3452
|
+
with mtx:
|
3453
|
+
if verbose and log:
|
3454
|
+
log("hook(%s) %r sending |%d|" % (src, cmd, len(msg)), 6)
|
3455
|
+
|
3456
|
+
sck.send_string(msg) # PUSH can safely timeout here
|
3457
|
+
|
3458
|
+
if mode == "req":
|
3459
|
+
if verbose and log:
|
3460
|
+
log("hook(%s) %r awaiting ack from req" % (src, cmd), 6)
|
3461
|
+
try:
|
3462
|
+
ret = sck.recv().decode("utf-8", "replace")
|
3463
|
+
except:
|
3464
|
+
sck.close()
|
3465
|
+
del ZMQ[cmd] # bad state; must reset
|
3466
|
+
raise Exception("ack timeout; zmq socket killed")
|
3467
|
+
|
3468
|
+
if ret and log:
|
3469
|
+
log("hook(%s) %r ACK: %r" % (src, cmd, ret), 6)
|
3470
|
+
|
3471
|
+
if wait:
|
3472
|
+
wait -= time.time() - t0
|
3473
|
+
if wait > 0:
|
3474
|
+
time.sleep(wait)
|
3475
|
+
|
3476
|
+
return ret
|
3477
|
+
|
3478
|
+
|
3345
3479
|
def _runhook(
|
3346
3480
|
log ,
|
3481
|
+
verbose ,
|
3347
3482
|
src ,
|
3348
3483
|
cmd ,
|
3349
3484
|
ap ,
|
@@ -3384,6 +3519,15 @@ def _runhook(
|
|
3384
3519
|
else:
|
3385
3520
|
arg = txt or ap
|
3386
3521
|
|
3522
|
+
if acmd[0].startswith("zmq:"):
|
3523
|
+
zs = "zmq-error"
|
3524
|
+
try:
|
3525
|
+
zs = _zmq_hook(log, verbose, src, acmd[0][4:].lower(), arg, wait, sp_ka)
|
3526
|
+
except Exception as ex:
|
3527
|
+
if log:
|
3528
|
+
log("zeromq failed: %r" % (ex,))
|
3529
|
+
return {"rc": 0, "stdout": zs}
|
3530
|
+
|
3387
3531
|
acmd += [arg]
|
3388
3532
|
if acmd[0].endswith(".py"):
|
3389
3533
|
acmd = [pybin] + acmd
|
@@ -3412,9 +3556,10 @@ def _runhook(
|
|
3412
3556
|
except:
|
3413
3557
|
ret = {"rc": rc, "stdout": v}
|
3414
3558
|
|
3415
|
-
wait
|
3416
|
-
|
3417
|
-
|
3559
|
+
if wait:
|
3560
|
+
wait -= time.time() - t0
|
3561
|
+
if wait > 0:
|
3562
|
+
time.sleep(wait)
|
3418
3563
|
|
3419
3564
|
return ret
|
3420
3565
|
|
@@ -3437,14 +3582,15 @@ def runhook(
|
|
3437
3582
|
txt ,
|
3438
3583
|
) :
|
3439
3584
|
args = (broker or up2k).args
|
3585
|
+
verbose = args.hook_v
|
3440
3586
|
vp = vp.replace("\\", "/")
|
3441
3587
|
ret = {"rc": 0}
|
3442
3588
|
for cmd in cmds:
|
3443
3589
|
try:
|
3444
3590
|
hr = _runhook(
|
3445
|
-
log, src, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt
|
3591
|
+
log, verbose, src, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt
|
3446
3592
|
)
|
3447
|
-
if
|
3593
|
+
if verbose and log:
|
3448
3594
|
log("hook(%s) %r => \033[32m%s" % (src, cmd, hr), 6)
|
3449
3595
|
if not hr:
|
3450
3596
|
return {}
|
copyparty/web/a/u2c.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
S_VERSION = "2.
|
5
|
-
S_BUILD_DT = "
|
4
|
+
S_VERSION = "2.8"
|
5
|
+
S_BUILD_DT = "2025-01-21"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -1247,7 +1247,7 @@ class Ctl(object):
|
|
1247
1247
|
for n, zsii in enumerate(file.cids)
|
1248
1248
|
]
|
1249
1249
|
print("chs: %s\n%s" % (vp, "\n".join(zsl)))
|
1250
|
-
zsl = [self.ar.wsalt, str(file.size)] + [x[0] for x in file.
|
1250
|
+
zsl = [self.ar.wsalt, str(file.size)] + [x[0] for x in file.cids]
|
1251
1251
|
zb = hashlib.sha512("\n".join(zsl).encode("utf-8")).digest()[:33]
|
1252
1252
|
wark = ub64enc(zb).decode("utf-8")
|
1253
1253
|
if self.ar.jw:
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/svcs.html
CHANGED
@@ -239,7 +239,7 @@
|
|
239
239
|
<div class="os win">
|
240
240
|
<h1>ShareX</h1>
|
241
241
|
|
242
|
-
<p>to upload screenshots using ShareX <a href="https://github.com/ShareX/ShareX/releases/tag/v12.
|
242
|
+
<p>to upload screenshots using ShareX <a href="https://github.com/ShareX/ShareX/releases/tag/v12.1.1">v12</a> or <a href="https://getsharex.com/">v15+</a>, save this as <code>copyparty.sxcu</code> and run it:</p>
|
243
243
|
|
244
244
|
<pre class="dl" name="copyparty.sxcu">
|
245
245
|
{ "Name": "copyparty",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.9
|
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
|
@@ -52,6 +52,8 @@ Provides-Extra: tftpd
|
|
52
52
|
Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
|
53
53
|
Provides-Extra: pwhash
|
54
54
|
Requires-Dist: argon2-cffi; extra == "pwhash"
|
55
|
+
Provides-Extra: zeromq
|
56
|
+
Requires-Dist: pyzmq; extra == "zeromq"
|
55
57
|
|
56
58
|
<img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
|
57
59
|
|
@@ -135,6 +137,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
135
137
|
* [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
|
136
138
|
* [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
|
137
139
|
* [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
|
140
|
+
* [zeromq](#zeromq) - event-hooks can send zeromq messages
|
138
141
|
* [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
|
139
142
|
* [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
|
140
143
|
* [ip auth](#ip-auth) - autologin based on IP range (CIDR)
|
@@ -670,8 +673,8 @@ select which type of archive you want in the `[⚙️] config` tab:
|
|
670
673
|
| `pax` | `?tar=pax` | pax-format tar, futureproof, not as fast |
|
671
674
|
| `tgz` | `?tar=gz` | gzip compressed gnu-tar (slow), for `curl \| tar -xvz` |
|
672
675
|
| `txz` | `?tar=xz` | gnu-tar with xz / lzma compression (v.slow) |
|
673
|
-
| `zip` | `?zip
|
674
|
-
| `zip_dos` | `?zip` | traditional cp437 (no unicode) to fix glitchy filenames |
|
676
|
+
| `zip` | `?zip` | works everywhere, glitchy filenames on win7 and older |
|
677
|
+
| `zip_dos` | `?zip=dos` | traditional cp437 (no unicode) to fix glitchy filenames |
|
675
678
|
| `zip_crc` | `?zip=crc` | cp437 with crc32 computed early for truly ancient software |
|
676
679
|
|
677
680
|
* gzip default level is `3` (0=fast, 9=best), change with `?tar=gz:9`
|
@@ -679,7 +682,7 @@ select which type of archive you want in the `[⚙️] config` tab:
|
|
679
682
|
* bz2 default level is `2` (1=fast, 9=best), change with `?tar=bz2:9`
|
680
683
|
* hidden files ([dotfiles](#dotfiles)) are excluded unless account is allowed to list them
|
681
684
|
* `up2k.db` and `dir.txt` is always excluded
|
682
|
-
* bsdtar supports streaming unzipping: `curl foo?zip
|
685
|
+
* bsdtar supports streaming unzipping: `curl foo?zip | bsdtar -xv`
|
683
686
|
* good, because copyparty's zip is faster than tar on small files
|
684
687
|
* `zip_crc` will take longer to download since the server has to read each file twice
|
685
688
|
* this is only to support MS-DOS PKZIP v2.04g (october 1993) and older
|
@@ -1513,6 +1516,23 @@ there's a bunch of flags and stuff, see `--help-hooks`
|
|
1513
1516
|
if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
|
1514
1517
|
|
1515
1518
|
|
1519
|
+
### zeromq
|
1520
|
+
|
1521
|
+
event-hooks can send zeromq messages instead of running programs
|
1522
|
+
|
1523
|
+
to send a 0mq message every time a file is uploaded,
|
1524
|
+
|
1525
|
+
* `--xau zmq:pub:tcp://*:5556` sends a PUB to any/all connected SUB clients
|
1526
|
+
* `--xau t3,zmq:push:tcp://*:5557` sends a PUSH to exactly one connected PULL client
|
1527
|
+
* `--xau t3,j,zmq:req:tcp://localhost:5555` sends a REQ to the connected REP client
|
1528
|
+
|
1529
|
+
the PUSH and REQ examples have `t3` (timeout after 3 seconds) because they block if there's no clients to talk to
|
1530
|
+
|
1531
|
+
* the REQ example does `t3,j` to send extended upload-info as json instead of just the filesystem-path
|
1532
|
+
|
1533
|
+
see [zmq-recv.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/zmq-recv.py) if you need something to receive the messages with
|
1534
|
+
|
1535
|
+
|
1516
1536
|
### upload events
|
1517
1537
|
|
1518
1538
|
the older, more powerful approach ([examples](./bin/mtag/)):
|
@@ -1600,12 +1620,16 @@ connecting to an aws s3 bucket and similar
|
|
1600
1620
|
|
1601
1621
|
there is no built-in support for this, but you can use FUSE-software such as [rclone](https://rclone.org/) / [geesefs](https://github.com/yandex-cloud/geesefs) / [JuiceFS](https://juicefs.com/en/) to first mount your cloud storage as a local disk, and then let copyparty use (a folder in) that disk as a volume
|
1602
1622
|
|
1603
|
-
you
|
1623
|
+
you will probably get decent speeds with the default config, however most likely restricted to using one TCP connection per file, so the upload-client won't be able to send multiple chunks in parallel
|
1624
|
+
|
1625
|
+
> before [v1.13.5](https://github.com/9001/copyparty/releases/tag/v1.13.5) it was recommended to use the volflag `sparse` to force-allow multiple chunks in parallel; this would improve the upload-speed from `1.5 MiB/s` to over `80 MiB/s` at the risk of provoking latent bugs in S3 or JuiceFS. But v1.13.5 added chunk-stitching, so this is now probably much less important. On the contrary, `nosparse` *may* now increase performance in some cases. Please try all three options (default, `sparse`, `nosparse`) as the optimal choice depends on your network conditions and software stack (both the FUSE-driver and cloud-server)
|
1604
1626
|
|
1605
1627
|
someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
|
1606
1628
|
|
1607
1629
|
you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
|
1608
1630
|
|
1631
|
+
> if you've experimented with this and made interesting observations, please share your findings so we can add a section with specific recommendations :-)
|
1632
|
+
|
1609
1633
|
|
1610
1634
|
## hiding from google
|
1611
1635
|
|
@@ -2359,13 +2383,13 @@ mandatory deps:
|
|
2359
2383
|
|
2360
2384
|
install these to enable bonus features
|
2361
2385
|
|
2362
|
-
enable hashed passwords in config: `argon2-cffi`
|
2386
|
+
enable [hashed passwords](#password-hashing) in config: `argon2-cffi`
|
2363
2387
|
|
2364
|
-
enable ftp-server:
|
2388
|
+
enable [ftp-server](#ftp-server):
|
2365
2389
|
* for just plaintext FTP, `pyftpdlib` (is built into the SFX)
|
2366
2390
|
* with TLS encryption, `pyftpdlib pyopenssl`
|
2367
2391
|
|
2368
|
-
enable music tags:
|
2392
|
+
enable [music tags](#metadata-from-audio-files):
|
2369
2393
|
* either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
|
2370
2394
|
* or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
|
2371
2395
|
|
@@ -2376,8 +2400,9 @@ enable [thumbnails](#thumbnails) of...
|
|
2376
2400
|
* **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin`
|
2377
2401
|
* **JPEG XL pictures:** `pyvips` or `ffmpeg`
|
2378
2402
|
|
2379
|
-
enable [
|
2380
|
-
|
2403
|
+
enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
|
2404
|
+
|
2405
|
+
enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
|
2381
2406
|
|
2382
2407
|
`pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
|
2383
2408
|
|
@@ -1,17 +1,17 @@
|
|
1
1
|
copyparty/__init__.py,sha256=VR6ZZhB9IxaK5TDXDTBM_OIP5ydkrdbaEnstktLM__s,2649
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=OvcLYTmA_IbuoA7PzqfozlfMUoWVhgK8OZ89htVQeHQ,114236
|
3
|
+
copyparty/__version__.py,sha256=rMDKjaOJgDxkWi5DqhkiIl0LpXkT0uLtMhbMTaIUfuM,251
|
4
|
+
copyparty/authsrv.py,sha256=uADnPkHiTH0UcBUr-w5hdUare6p-74O7cJQaL9lkpws,104513
|
5
5
|
copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
|
6
6
|
copyparty/broker_mpw.py,sha256=PpSS4SK3pItlpfD8OwVr3QmJEPKlUgaf2nuMOozixgU,3347
|
7
7
|
copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
|
8
8
|
copyparty/broker_util.py,sha256=76mfnFOpX1gUUvtjm8UQI7jpTIaVINX10QonM-B7ggc,1680
|
9
9
|
copyparty/cert.py,sha256=0ZAPeXeMR164vWn9GQU3JDKooYXEq_NOQkDeg543ivg,8009
|
10
|
-
copyparty/cfg.py,sha256=
|
11
|
-
copyparty/dxml.py,sha256=
|
10
|
+
copyparty/cfg.py,sha256=WY4gMZ42T-mBitZivxh5wcN1JIN4i2m8Gg8kGumnDPw,10619
|
11
|
+
copyparty/dxml.py,sha256=vu5uZQtwvwoqnFHbULs2Zh_y2DETu0T-ENpMZ1i2CV4,2505
|
12
12
|
copyparty/fsutil.py,sha256=IVOFG8zBQPMQDDv7RIStSJHwHiAnVNROZS37O5k465A,4524
|
13
13
|
copyparty/ftpd.py,sha256=T97SFS7JFtvRLbJX8C4fJSYwe13vhN3-E6emtlVmqLA,17608
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=lTMSK9xLXhRsPo1XPeV_RRTJZ6jQgx17wt_BFdQ26M4,215837
|
15
15
|
copyparty/httpconn.py,sha256=mQSgljh0Q-jyWjF4tQLrHbRKRe9WKl19kGqsGMsJpWo,6880
|
16
16
|
copyparty/httpsrv.py,sha256=pxH_Eh8ElBLvOEDejgpP9Bvk65HNEou-03aYIcgXhrs,18090
|
17
17
|
copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
|
@@ -24,15 +24,15 @@ copyparty/smbd.py,sha256=dixFl2wlWymq_Cycc8a4cVB4gY8RSg2e3tE7Xr-aDa0,14614
|
|
24
24
|
copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
|
25
25
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
26
26
|
copyparty/sutil.py,sha256=6zEEGl4hRe6bTB83Y_RtnBGxr2JcUa__GdiAMqNJZnY,3208
|
27
|
-
copyparty/svchub.py,sha256=
|
27
|
+
copyparty/svchub.py,sha256=mgZ2UndrMqWuUywecsCgVz488WoS0EFHR94VvWZjeT0,41454
|
28
28
|
copyparty/szip.py,sha256=HFtnwOiBgx0HMLUf-h_T84zSlRijPxmhRo5PM613kRA,8602
|
29
29
|
copyparty/tcpsrv.py,sha256=2q18dGR8jnezA4SMfUXa-wrGRGX3nHIwkxkWvkTzF2A,19889
|
30
30
|
copyparty/tftpd.py,sha256=PXgG4rTmiaU_TavSyZWD5cFphdfChs9YvNY21qfExt8,13611
|
31
31
|
copyparty/th_cli.py,sha256=1B8el4NNs5cNyJyjOPiAdvLOX2HQXaebsHn6VLdZ_gU,4630
|
32
32
|
copyparty/th_srv.py,sha256=uAcz-wZJQEG5KavcZDkwToONZujyoOeC4oCxxKTD5us,29575
|
33
33
|
copyparty/u2idx.py,sha256=G6MDbD4I_sJSOwaNFZ6XLTQhnEDrB12pVKuKhzQ_leE,13676
|
34
|
-
copyparty/up2k.py,sha256=
|
35
|
-
copyparty/util.py,sha256=
|
34
|
+
copyparty/up2k.py,sha256=alObSL1EVyPedi_24s7DBFlBzA0ZMkr9_jOtzdRV3vk,175427
|
35
|
+
copyparty/util.py,sha256=Msbj0esxQNmEEOheL6ffubMeyPLEqyRnMJ1g5t2pI68,99012
|
36
36
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
copyparty/bos/bos.py,sha256=Wb7eWsXJgR5AFlBR9ZOyKrLTwy-Kct9RrGiOu4Jo37Y,1622
|
38
38
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
@@ -57,7 +57,7 @@ copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8
|
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=_amC3ipOrXKEFz8DsVP-JEl49VjMQYiKyF78eWfG-uk,7965
|
58
58
|
copyparty/web/browser.css.gz,sha256=kurx_iA-KxLYx8PqJsn0bJVjkAxP-0YTOHSV9l_oouo,11645
|
59
59
|
copyparty/web/browser.html,sha256=dekrZQ6w8ciB-QPlp-mjcuzUVKlsCYcvvi6efmXRfQE,4822
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=V9_Xz8uZsJ01MNoc480L0SMduAOINGrcQ2296FNRoeA,89860
|
61
61
|
copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
|
62
62
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
63
63
|
copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
|
@@ -80,7 +80,7 @@ copyparty/web/shares.js.gz,sha256=emeY2-wjkh8x1JgaW6ny5fcC7XpZzZzfE1f-sEyntQ4,94
|
|
80
80
|
copyparty/web/splash.css.gz,sha256=S8_A7JJl71xACRBYGzafeaD82OacW6Fa7oKPiNyrhAs,1087
|
81
81
|
copyparty/web/splash.html,sha256=QEnTH9QZXFmAuyVtgqOuuHKBtIdi7uclpRqe0ZMewj4,6249
|
82
82
|
copyparty/web/splash.js.gz,sha256=4VqNznN10-bT33IJm3VWzBEJ1s08XZyxFB1TYPUkuAo,2739
|
83
|
-
copyparty/web/svcs.html,sha256=
|
83
|
+
copyparty/web/svcs.html,sha256=dnE1fG15zOpq7u0GYt8ij6BUv_LTwsiipFeneVYlMsM,14140
|
84
84
|
copyparty/web/svcs.js.gz,sha256=rcc75HMmoc3KA7Ld2j8X9AKX_elZgwUD6Vnm2F-yj_U,805
|
85
85
|
copyparty/web/ui.css.gz,sha256=0sHIwGsL3_xH8Uu6N0Ag3bKBTjf-e_yfFbKynEZXAnk,2800
|
86
86
|
copyparty/web/up2k.js.gz,sha256=f00wmaThk1CoFYzFBG_6KLG0acq60cAn3p12tngqprk,23843
|
@@ -88,7 +88,7 @@ copyparty/web/util.js.gz,sha256=uCCnKWT_FeG-ShKPoj0MtXnBwtdAbyDSM9AP9KiBDjw,1509
|
|
88
88
|
copyparty/web/w.hash.js.gz,sha256=l3GpSJD6mcU-1CRWkIj7PybgbjlfSr8oeO3vortIrQk,1105
|
89
89
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
90
|
copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
|
91
|
-
copyparty/web/a/u2c.py,sha256=
|
91
|
+
copyparty/web/a/u2c.py,sha256=N9NZHF6CbooNxIYkZMVz7wWTMh88nXCXcd4bDKzaanw,51603
|
92
92
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
93
93
|
copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
|
94
94
|
copyparty/web/dd/3.png,sha256=4lho8Koz5tV7jJ4ODo6GMTScZfkqsT05yp48EDFIlyg,252
|
@@ -109,9 +109,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
109
109
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
110
110
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
111
111
|
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
112
|
-
copyparty-1.16.
|
113
|
-
copyparty-1.16.
|
114
|
-
copyparty-1.16.
|
115
|
-
copyparty-1.16.
|
116
|
-
copyparty-1.16.
|
117
|
-
copyparty-1.16.
|
112
|
+
copyparty-1.16.9.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
113
|
+
copyparty-1.16.9.dist-info/METADATA,sha256=-gjl5i-kYVmjMeHdJ3ZXxeAu0FFWH2zcD0LTu2rb-Cw,145641
|
114
|
+
copyparty-1.16.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
115
|
+
copyparty-1.16.9.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
116
|
+
copyparty-1.16.9.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
117
|
+
copyparty-1.16.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|