copyparty 1.16.2__py3-none-any.whl → 1.16.4__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 +5 -1
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +19 -0
- copyparty/cfg.py +2 -0
- copyparty/httpcli.py +96 -19
- copyparty/mdns.py +7 -0
- copyparty/res/COPYING.txt +59 -2
- copyparty/stolen/dnslib/dns.py +2 -2
- copyparty/stolen/dnslib/label.py +21 -1
- copyparty/svchub.py +1 -1
- copyparty/u2idx.py +23 -20
- copyparty/up2k.py +38 -14
- copyparty/util.py +20 -1
- copyparty/web/a/u2c.py +53 -7
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/easymde.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/deps/sha512.hw.js.gz +0 -0
- copyparty/web/md.js.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/METADATA +6 -3
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/RECORD +29 -29
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/LICENSE +0 -0
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/WHEEL +0 -0
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/entry_points.txt +0 -0
- {copyparty-1.16.2.dist-info → copyparty-1.16.4.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -1116,6 +1116,8 @@ def add_zc_mdns(ap):
|
|
1116
1116
|
ap2.add_argument("--zm6", action="store_true", help="IPv6 only")
|
1117
1117
|
ap2.add_argument("--zmv", action="store_true", help="verbose mdns")
|
1118
1118
|
ap2.add_argument("--zmvv", action="store_true", help="verboser mdns")
|
1119
|
+
ap2.add_argument("--zm-no-pe", action="store_true", help="mute parser errors (invalid incoming MDNS packets)")
|
1120
|
+
ap2.add_argument("--zm-nwa-1", action="store_true", help="disable workaround for avahi-bug #379 (corruption in Avahi's mDNS reflection feature)")
|
1119
1121
|
ap2.add_argument("--zms", metavar="dhf", type=u, default="", help="list of services to announce -- d=webdav h=http f=ftp s=smb -- lowercase=plaintext uppercase=TLS -- default: all enabled services except http/https (\033[32mDdfs\033[0m if \033[33m--ftp\033[0m and \033[33m--smb\033[0m is set, \033[32mDd\033[0m otherwise)")
|
1120
1122
|
ap2.add_argument("--zm-ld", metavar="PATH", type=u, default="", help="link a specific folder for webdav shares")
|
1121
1123
|
ap2.add_argument("--zm-lh", metavar="PATH", type=u, default="", help="link a specific folder for http shares")
|
@@ -1308,7 +1310,7 @@ def add_logging(ap):
|
|
1308
1310
|
ap2.add_argument("--log-htp", action="store_true", help="debug: print http-server threadpool scaling")
|
1309
1311
|
ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
1310
1312
|
ap2.add_argument("--ohead", metavar="HEADER", type=u, action='append', help="print response \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
1311
|
-
ap2.add_argument("--lf-url", metavar="RE", type=u, default=r"^/\.cpr
|
1313
|
+
ap2.add_argument("--lf-url", metavar="RE", type=u, default=r"^/\.cpr/|[?&]th=[wjp]|/\.(_|ql_|DS_Store$|localized$)", help="dont log URLs matching regex \033[33mRE\033[0m")
|
1312
1314
|
|
1313
1315
|
|
1314
1316
|
def add_admin(ap):
|
@@ -1393,6 +1395,7 @@ def add_db_general(ap, hcores):
|
|
1393
1395
|
ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
|
1394
1396
|
ap2.add_argument("--srch-time", metavar="SEC", type=int, default=45, help="search deadline -- terminate searches running for more than \033[33mSEC\033[0m seconds")
|
1395
1397
|
ap2.add_argument("--srch-hits", metavar="N", type=int, default=7999, help="max search results to allow clients to fetch; 125 results will be shown initially")
|
1398
|
+
ap2.add_argument("--srch-excl", metavar="PTN", type=u, default="", help="regex: exclude files from search results if the file-URL matches \033[33mPTN\033[0m (case-sensitive). Example: [\033[32mpassword|logs/[0-9]\033[0m] any URL containing 'password' or 'logs/DIGIT' (volflag=srch_excl)")
|
1396
1399
|
ap2.add_argument("--dotsrch", action="store_true", help="show dotfiles in search results (volflags: dotsrch | nodotsrch)")
|
1397
1400
|
|
1398
1401
|
|
@@ -1450,6 +1453,7 @@ def add_ui(ap, retry):
|
|
1450
1453
|
ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")
|
1451
1454
|
ap2.add_argument("--sort", metavar="C,C,C", type=u, default="href", help="default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: \033[32mhref -href ext sz ts tags/Album tags/.tn\033[0m (volflag=sort)")
|
1452
1455
|
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
1456
|
+
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
1453
1457
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
1454
1458
|
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
1455
1459
|
ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -1873,6 +1873,7 @@ class AuthSrv(object):
|
|
1873
1873
|
["no_hash", "nohash"],
|
1874
1874
|
["no_idx", "noidx"],
|
1875
1875
|
["og_ua", "og_ua"],
|
1876
|
+
["srch_excl", "srch_excl"],
|
1876
1877
|
]:
|
1877
1878
|
if vf in vol.flags:
|
1878
1879
|
ptn = re.compile(vol.flags.pop(vf))
|
@@ -2079,6 +2080,22 @@ class AuthSrv(object):
|
|
2079
2080
|
self.log(t.format(mtp), 1)
|
2080
2081
|
errors = True
|
2081
2082
|
|
2083
|
+
for vol in vfs.all_vols.values():
|
2084
|
+
re1 = vol.flags.get("srch_excl")
|
2085
|
+
excl = [re1.pattern] if re1 else []
|
2086
|
+
|
2087
|
+
vpaths = []
|
2088
|
+
vtop = vol.vpath
|
2089
|
+
for vp2 in vfs.all_vols.keys():
|
2090
|
+
if vp2.startswith((vtop + "/").lstrip("/")) and vtop != vp2:
|
2091
|
+
vpaths.append(re.escape(vp2[len(vtop) :].lstrip("/")))
|
2092
|
+
if vpaths:
|
2093
|
+
excl.append("^(%s)/" % ("|".join(vpaths),))
|
2094
|
+
|
2095
|
+
vol.flags["srch_re_dots"] = re.compile("|".join(excl or ["^$"]))
|
2096
|
+
excl.extend([r"^\.", r"/\."])
|
2097
|
+
vol.flags["srch_re_nodot"] = re.compile("|".join(excl))
|
2098
|
+
|
2082
2099
|
have_daw = False
|
2083
2100
|
for vol in vfs.all_nodes.values():
|
2084
2101
|
daw = vol.flags.get("daw") or self.args.daw
|
@@ -2307,6 +2324,7 @@ class AuthSrv(object):
|
|
2307
2324
|
"idx": "e2d" in vf,
|
2308
2325
|
"itag": "e2t" in vf,
|
2309
2326
|
"dnsort": "nsort" in vf,
|
2327
|
+
"dhsortn": vf["hsortn"],
|
2310
2328
|
"dsort": vf["sort"],
|
2311
2329
|
"dcrop": vf["crop"],
|
2312
2330
|
"dth3x": vf["th3x"],
|
@@ -2332,6 +2350,7 @@ class AuthSrv(object):
|
|
2332
2350
|
"dgrid": "grid" in vf,
|
2333
2351
|
"dgsel": "gsel" in vf,
|
2334
2352
|
"dnsort": "nsort" in vf,
|
2353
|
+
"dhsortn": vf["hsortn"],
|
2335
2354
|
"dsort": vf["sort"],
|
2336
2355
|
"dcrop": vf["crop"],
|
2337
2356
|
"dth3x": vf["th3x"],
|
copyparty/cfg.py
CHANGED
@@ -70,6 +70,7 @@ def vf_vmap() :
|
|
70
70
|
}
|
71
71
|
for k in (
|
72
72
|
"dbd",
|
73
|
+
"hsortn",
|
73
74
|
"html_head",
|
74
75
|
"lg_sbf",
|
75
76
|
"md_sbf",
|
@@ -191,6 +192,7 @@ flagcats = {
|
|
191
192
|
"xvol": "do not follow symlinks leaving the volume root",
|
192
193
|
"dotsrch": "show dotfiles in search results",
|
193
194
|
"nodotsrch": "hide dotfiles in search results (default)",
|
195
|
+
"srch_excl": "exclude search results with URL matching this regex",
|
194
196
|
},
|
195
197
|
'database, audio tags\n"mte", "mth", "mtp", "mtm" all work the same as -mte, -mth, ...': {
|
196
198
|
"mtp=.bpm=f,audio-bpm.py": 'uses the "audio-bpm.py" program to\ngenerate ".bpm" tags from uploads (f = overwrite tags)',
|
copyparty/httpcli.py
CHANGED
@@ -14,6 +14,7 @@ import re
|
|
14
14
|
import socket
|
15
15
|
import stat
|
16
16
|
import string
|
17
|
+
import sys
|
17
18
|
import threading # typechk
|
18
19
|
import time
|
19
20
|
import uuid
|
@@ -76,6 +77,7 @@ from .util import (
|
|
76
77
|
html_escape,
|
77
78
|
humansize,
|
78
79
|
ipnorm,
|
80
|
+
justcopy,
|
79
81
|
load_resource,
|
80
82
|
loadpy,
|
81
83
|
log_reloc,
|
@@ -120,6 +122,8 @@ if not hasattr(socket, "AF_UNIX"):
|
|
120
122
|
|
121
123
|
_ = (argparse, threading)
|
122
124
|
|
125
|
+
USED4SEC = {"usedforsecurity": False} if sys.version_info > (3, 9) else {}
|
126
|
+
|
123
127
|
NO_CACHE = {"Cache-Control": "no-cache"}
|
124
128
|
|
125
129
|
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
|
@@ -133,6 +137,10 @@ READMES = [[0, ["preadme.md", "PREADME.md"]], [1, ["readme.md", "README.md"]]]
|
|
133
137
|
|
134
138
|
RSS_SORT = {"m": "mt", "u": "at", "n": "fn", "s": "sz"}
|
135
139
|
|
140
|
+
A_FILE = os.stat_result(
|
141
|
+
(0o644, -1, -1, 1, 1000, 1000, 8, 0x39230101, 0x39230101, 0x39230101)
|
142
|
+
)
|
143
|
+
|
136
144
|
|
137
145
|
class HttpCli(object):
|
138
146
|
"""
|
@@ -1238,7 +1246,7 @@ class HttpCli(object):
|
|
1238
1246
|
self.log("RSS %s @%s" % (self.req, self.uname))
|
1239
1247
|
|
1240
1248
|
if not self.can_read:
|
1241
|
-
return self.tx_404()
|
1249
|
+
return self.tx_404(True)
|
1242
1250
|
|
1243
1251
|
vn = self.vn
|
1244
1252
|
if not vn.flags.get("rss"):
|
@@ -1419,7 +1427,8 @@ class HttpCli(object):
|
|
1419
1427
|
|
1420
1428
|
depth = self.headers.get("depth", "infinity").lower()
|
1421
1429
|
if depth == "infinity":
|
1422
|
-
|
1430
|
+
# allow depth:0 from unmapped root, but require read-axs otherwise
|
1431
|
+
if not self.can_read and (self.vpath or self.asrv.vfs.realpath):
|
1423
1432
|
t = "depth:infinity requires read-access in /%s"
|
1424
1433
|
t = t % (self.vpath,)
|
1425
1434
|
self.log(t, 3)
|
@@ -1479,7 +1488,7 @@ class HttpCli(object):
|
|
1479
1488
|
t2 = " or 'infinity'" if self.args.dav_inf else ""
|
1480
1489
|
raise Pebkac(412, t.format(depth, t2))
|
1481
1490
|
|
1482
|
-
if not self.can_read and not self.can_write and not
|
1491
|
+
if not self.can_read and not self.can_write and not fgen:
|
1483
1492
|
self.log("inaccessible: [%s]" % (self.vpath,))
|
1484
1493
|
raise Pebkac(401, "authenticate")
|
1485
1494
|
|
@@ -1758,7 +1767,7 @@ class HttpCli(object):
|
|
1758
1767
|
|
1759
1768
|
if not self.can_write:
|
1760
1769
|
t = "user %s does not have write-access under /%s"
|
1761
|
-
raise Pebkac(403, t % (self.uname, self.vn.vpath))
|
1770
|
+
raise Pebkac(403 if self.pw else 401, t % (self.uname, self.vn.vpath))
|
1762
1771
|
|
1763
1772
|
if not self.args.no_dav and self._applesan():
|
1764
1773
|
return self.headers.get("content-length") == "0"
|
@@ -2049,10 +2058,31 @@ class HttpCli(object):
|
|
2049
2058
|
# small toctou, but better than clobbering a hardlink
|
2050
2059
|
wunlink(self.log, path, vfs.flags)
|
2051
2060
|
|
2061
|
+
hasher = None
|
2062
|
+
copier = hashcopy
|
2063
|
+
if "ck" in self.ouparam or "ck" in self.headers:
|
2064
|
+
zs = self.ouparam.get("ck") or self.headers.get("ck") or ""
|
2065
|
+
if not zs or zs == "no":
|
2066
|
+
copier = justcopy
|
2067
|
+
elif zs == "md5":
|
2068
|
+
hasher = hashlib.md5(**USED4SEC)
|
2069
|
+
elif zs == "sha1":
|
2070
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2071
|
+
elif zs == "sha256":
|
2072
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2073
|
+
elif zs in ("blake2", "b2"):
|
2074
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2075
|
+
elif zs in ("blake2s", "b2s"):
|
2076
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2077
|
+
elif zs == "sha512":
|
2078
|
+
pass
|
2079
|
+
else:
|
2080
|
+
raise Pebkac(500, "unknown hash alg")
|
2081
|
+
|
2052
2082
|
f, fn = ren_open(fn, *open_a, **params)
|
2053
2083
|
try:
|
2054
2084
|
path = os.path.join(fdir, fn)
|
2055
|
-
post_sz, sha_hex, sha_b64 =
|
2085
|
+
post_sz, sha_hex, sha_b64 = copier(reader, f, hasher, 0, self.args.s_wr_slp)
|
2056
2086
|
finally:
|
2057
2087
|
f.close()
|
2058
2088
|
|
@@ -2289,8 +2319,8 @@ class HttpCli(object):
|
|
2289
2319
|
# kinda silly but has the least side effects
|
2290
2320
|
return self.handle_new_md()
|
2291
2321
|
|
2292
|
-
if act
|
2293
|
-
return self.handle_plain_upload(file0)
|
2322
|
+
if act in ("bput", "uput"):
|
2323
|
+
return self.handle_plain_upload(file0, act == "uput")
|
2294
2324
|
|
2295
2325
|
if act == "tput":
|
2296
2326
|
return self.handle_text_upload()
|
@@ -2901,13 +2931,41 @@ class HttpCli(object):
|
|
2901
2931
|
)
|
2902
2932
|
|
2903
2933
|
def handle_plain_upload(
|
2904
|
-
self,
|
2934
|
+
self,
|
2935
|
+
file0 ,
|
2936
|
+
nohash ,
|
2905
2937
|
) :
|
2906
2938
|
assert self.parser
|
2907
2939
|
nullwrite = self.args.nw
|
2908
2940
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2909
2941
|
self._assert_safe_rem(rem)
|
2910
2942
|
|
2943
|
+
halg = "sha512"
|
2944
|
+
hasher = None
|
2945
|
+
copier = hashcopy
|
2946
|
+
if nohash:
|
2947
|
+
halg = ""
|
2948
|
+
copier = justcopy
|
2949
|
+
elif "ck" in self.ouparam or "ck" in self.headers:
|
2950
|
+
halg = self.ouparam.get("ck") or self.headers.get("ck") or ""
|
2951
|
+
if not halg or halg == "no":
|
2952
|
+
copier = justcopy
|
2953
|
+
halg = ""
|
2954
|
+
elif halg == "md5":
|
2955
|
+
hasher = hashlib.md5(**USED4SEC)
|
2956
|
+
elif halg == "sha1":
|
2957
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2958
|
+
elif halg == "sha256":
|
2959
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2960
|
+
elif halg in ("blake2", "b2"):
|
2961
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2962
|
+
elif halg in ("blake2s", "b2s"):
|
2963
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2964
|
+
elif halg == "sha512":
|
2965
|
+
pass
|
2966
|
+
else:
|
2967
|
+
raise Pebkac(500, "unknown hash alg")
|
2968
|
+
|
2911
2969
|
upload_vpath = self.vpath
|
2912
2970
|
lim = vfs.get_dbv(rem)[0].lim
|
2913
2971
|
fdir_base = vfs.canonical(rem)
|
@@ -3037,8 +3095,8 @@ class HttpCli(object):
|
|
3037
3095
|
try:
|
3038
3096
|
tabspath = os.path.join(fdir, tnam)
|
3039
3097
|
self.log("writing to {}".format(tabspath))
|
3040
|
-
sz, sha_hex, sha_b64 =
|
3041
|
-
p_data, f,
|
3098
|
+
sz, sha_hex, sha_b64 = copier(
|
3099
|
+
p_data, f, hasher, max_sz, self.args.s_wr_slp
|
3042
3100
|
)
|
3043
3101
|
if sz == 0:
|
3044
3102
|
raise Pebkac(400, "empty files in post")
|
@@ -3170,10 +3228,15 @@ class HttpCli(object):
|
|
3170
3228
|
jmsg["error"] = errmsg
|
3171
3229
|
errmsg = "ERROR: " + errmsg
|
3172
3230
|
|
3231
|
+
if halg:
|
3232
|
+
file_fmt = '{0}: {1} // {2} // {3} bytes // <a href="/{4}">{5}</a> {6}\n'
|
3233
|
+
else:
|
3234
|
+
file_fmt = '{3} bytes // <a href="/{4}">{5}</a> {6}\n'
|
3235
|
+
|
3173
3236
|
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
3174
3237
|
vsuf = ""
|
3175
3238
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
3176
|
-
st = bos.stat(ap)
|
3239
|
+
st = A_FILE if nullwrite else bos.stat(ap)
|
3177
3240
|
alg = 2 if "fka" in vfs.flags else 1
|
3178
3241
|
vsuf = "?k=" + self.gen_fk(
|
3179
3242
|
alg,
|
@@ -3188,7 +3251,8 @@ class HttpCli(object):
|
|
3188
3251
|
|
3189
3252
|
vpath = "{}/{}".format(upload_vpath, lfn).strip("/")
|
3190
3253
|
rel_url = quotep(self.args.RS + vpath) + vsuf
|
3191
|
-
msg +=
|
3254
|
+
msg += file_fmt.format(
|
3255
|
+
halg,
|
3192
3256
|
sha_hex[:56],
|
3193
3257
|
sha_b64,
|
3194
3258
|
sz,
|
@@ -3204,13 +3268,14 @@ class HttpCli(object):
|
|
3204
3268
|
self.host,
|
3205
3269
|
rel_url,
|
3206
3270
|
),
|
3207
|
-
"sha512": sha_hex[:56],
|
3208
|
-
"sha_b64": sha_b64,
|
3209
3271
|
"sz": sz,
|
3210
3272
|
"fn": lfn,
|
3211
3273
|
"fn_orig": ofn,
|
3212
3274
|
"path": rel_url,
|
3213
3275
|
}
|
3276
|
+
if halg:
|
3277
|
+
jpart[halg] = sha_hex[:56]
|
3278
|
+
jpart["sha_b64"] = sha_b64
|
3214
3279
|
jmsg["files"].append(jpart)
|
3215
3280
|
|
3216
3281
|
vspd = self._spd(sz_total, False)
|
@@ -4603,6 +4668,18 @@ class HttpCli(object):
|
|
4603
4668
|
if "th" in self.ouparam:
|
4604
4669
|
return self.tx_svg("e" + pt[:3])
|
4605
4670
|
|
4671
|
+
# most webdav clients will not send credentials until they
|
4672
|
+
# get 401'd, so send a challenge if we're Absolutely Sure
|
4673
|
+
# that the client is not a graphical browser
|
4674
|
+
if (
|
4675
|
+
rc == 403
|
4676
|
+
and not self.pw
|
4677
|
+
and not self.ua.startswith("Mozilla/")
|
4678
|
+
and "sec-fetch-site" not in self.headers
|
4679
|
+
):
|
4680
|
+
rc = 401
|
4681
|
+
self.out_headers["WWW-Authenticate"] = 'Basic realm="a"'
|
4682
|
+
|
4606
4683
|
t = t.format(self.args.SR)
|
4607
4684
|
qv = quotep(self.vpaths) + self.ourlq()
|
4608
4685
|
html = self.j2s(
|
@@ -5243,7 +5320,7 @@ class HttpCli(object):
|
|
5243
5320
|
st = bos.stat(abspath)
|
5244
5321
|
except:
|
5245
5322
|
if "on404" not in vn.flags:
|
5246
|
-
return self.tx_404()
|
5323
|
+
return self.tx_404(not self.can_read)
|
5247
5324
|
|
5248
5325
|
ret = self.on40x(vn.flags["on404"], vn, rem)
|
5249
5326
|
if ret == "true":
|
@@ -5254,9 +5331,9 @@ class HttpCli(object):
|
|
5254
5331
|
try:
|
5255
5332
|
st = bos.stat(abspath)
|
5256
5333
|
except:
|
5257
|
-
return self.tx_404()
|
5334
|
+
return self.tx_404(not self.can_read)
|
5258
5335
|
else:
|
5259
|
-
return self.tx_404()
|
5336
|
+
return self.tx_404(not self.can_read)
|
5260
5337
|
|
5261
5338
|
if rem.startswith(".hist/up2k.") or (
|
5262
5339
|
rem.endswith("/dir.txt") and rem.startswith(".hist/th/")
|
@@ -5383,13 +5460,13 @@ class HttpCli(object):
|
|
5383
5460
|
vrem = vjoin(vrem, fn)
|
5384
5461
|
abspath = ap2
|
5385
5462
|
break
|
5386
|
-
elif self.vpath.rsplit("/", 1)[1] in ("index.htm", "index.html"):
|
5463
|
+
elif self.vpath.rsplit("/", 1)[-1] in ("index.htm", "index.html"):
|
5387
5464
|
fk_pass = True
|
5388
5465
|
|
5389
5466
|
if not is_dir and (self.can_read or self.can_get):
|
5390
5467
|
if not self.can_read and not fk_pass and "fk" in vn.flags:
|
5391
5468
|
if not use_filekey:
|
5392
|
-
return self.tx_404()
|
5469
|
+
return self.tx_404(True)
|
5393
5470
|
|
5394
5471
|
if add_og and not abspath.lower().endswith(".md"):
|
5395
5472
|
if og_ua or self.host not in self.headers.get("referer", ""):
|
copyparty/mdns.py
CHANGED
@@ -25,6 +25,7 @@ from .stolen.dnslib import (
|
|
25
25
|
DNSHeader,
|
26
26
|
DNSQuestion,
|
27
27
|
DNSRecord,
|
28
|
+
set_avahi_379,
|
28
29
|
)
|
29
30
|
from .util import CachedSet, Daemon, Netdev, list_ips, min_ex
|
30
31
|
|
@@ -68,6 +69,9 @@ class MDNS(MCast):
|
|
68
69
|
self.ngen = ngen
|
69
70
|
self.ttl = 300
|
70
71
|
|
72
|
+
if not self.args.zm_nwa_1:
|
73
|
+
set_avahi_379()
|
74
|
+
|
71
75
|
zs = self.args.name + ".local."
|
72
76
|
zs = zs.encode("ascii", "replace").decode("ascii", "replace")
|
73
77
|
self.hn = "-".join(x for x in zs.split("?") if x) or (
|
@@ -332,6 +336,9 @@ class MDNS(MCast):
|
|
332
336
|
self.log("stopped", 2)
|
333
337
|
return
|
334
338
|
|
339
|
+
if self.args.zm_no_pe:
|
340
|
+
continue
|
341
|
+
|
335
342
|
t = "{} {} \033[33m|{}| {}\n{}".format(
|
336
343
|
self.srv[sck].name, addr, len(buf), repr(buf)[2:-1], min_ex()
|
337
344
|
)
|
copyparty/res/COPYING.txt
CHANGED
@@ -75,21 +75,78 @@ Copyright (c) 2022 Fonticons, Inc.
|
|
75
75
|
License: SIL OFL 1.1
|
76
76
|
|
77
77
|
|
78
|
-
[07m--- MIT License ---[0m
|
79
78
|
|
80
79
|
|
81
80
|
|
82
|
-
[07m---
|
81
|
+
[07m--- MIT License ---[0m
|
82
|
+
|
83
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
83
84
|
|
85
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
84
86
|
|
87
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
85
88
|
|
86
89
|
[07m--- BSD 2-Clause License ---[0m
|
87
90
|
|
91
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
92
|
+
|
93
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
88
94
|
|
95
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
96
|
+
|
97
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
89
98
|
|
90
99
|
[07m--- BSD 3-Clause License ---[0m
|
91
100
|
|
101
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
102
|
+
|
103
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
104
|
+
|
105
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
92
106
|
|
107
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
108
|
+
|
109
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
93
110
|
|
94
111
|
[07m--- SIL Open Font License v1.1 ---[0m
|
95
112
|
|
113
|
+
PREAMBLE
|
114
|
+
|
115
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
116
|
+
|
117
|
+
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
118
|
+
|
119
|
+
DEFINITIONS
|
120
|
+
|
121
|
+
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
122
|
+
|
123
|
+
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
|
124
|
+
|
125
|
+
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
126
|
+
|
127
|
+
"Modified Version" refers to any derivative made by adding to, deleting, or substituting - in part or in whole - any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
128
|
+
|
129
|
+
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
130
|
+
|
131
|
+
PERMISSION & CONDITIONS
|
132
|
+
|
133
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
134
|
+
|
135
|
+
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
136
|
+
|
137
|
+
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
138
|
+
|
139
|
+
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
140
|
+
|
141
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
142
|
+
|
143
|
+
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
144
|
+
|
145
|
+
TERMINATION
|
146
|
+
|
147
|
+
This license becomes null and void if any of the above conditions are not met.
|
148
|
+
|
149
|
+
DISCLAIMER
|
150
|
+
|
151
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
152
|
+
|
copyparty/stolen/dnslib/dns.py
CHANGED
@@ -8,7 +8,7 @@ from itertools import chain
|
|
8
8
|
from .bimap import Bimap, BimapError
|
9
9
|
from .bit import get_bits, set_bits
|
10
10
|
from .buffer import BufferError
|
11
|
-
from .label import DNSBuffer, DNSLabel
|
11
|
+
from .label import DNSBuffer, DNSLabel, set_avahi_379
|
12
12
|
from .ranges import IP4, IP6, H, I, check_bytes
|
13
13
|
|
14
14
|
|
@@ -426,7 +426,7 @@ class RR(object):
|
|
426
426
|
if rdlength:
|
427
427
|
rdata = RDMAP.get(QTYPE.get(rtype), RD).parse(buffer, rdlength)
|
428
428
|
else:
|
429
|
-
rdata = ""
|
429
|
+
rdata = RD(b"a")
|
430
430
|
return cls(rname, rtype, rclass, ttl, rdata)
|
431
431
|
except (BufferError, BimapError) as e:
|
432
432
|
raise DNSError("Error unpacking RR [offset=%d]: %s" % (buffer.offset, e))
|
copyparty/stolen/dnslib/label.py
CHANGED
@@ -11,6 +11,23 @@ LDH = set(range(33, 127))
|
|
11
11
|
ESCAPE = re.compile(r"\\([0-9][0-9][0-9])")
|
12
12
|
|
13
13
|
|
14
|
+
avahi_379 = 0
|
15
|
+
|
16
|
+
|
17
|
+
def set_avahi_379():
|
18
|
+
global avahi_379
|
19
|
+
avahi_379 = 1
|
20
|
+
|
21
|
+
|
22
|
+
def log_avahi_379(args):
|
23
|
+
global avahi_379
|
24
|
+
if avahi_379 == 2:
|
25
|
+
return
|
26
|
+
avahi_379 = 2
|
27
|
+
t = "Invalid pointer in DNSLabel [offset=%d,pointer=%d,length=%d];\n\033[35m NOTE: this is probably avahi-bug #379, packet corruption in Avahi's mDNS-reflection feature. Copyparty has a workaround and is OK, but other devices need either --zm4 or --zm6"
|
28
|
+
raise BufferError(t % args)
|
29
|
+
|
30
|
+
|
14
31
|
class DNSLabelError(Exception):
|
15
32
|
pass
|
16
33
|
|
@@ -96,8 +113,11 @@ class DNSBuffer(Buffer):
|
|
96
113
|
)
|
97
114
|
if pointer < self.offset:
|
98
115
|
self.offset = pointer
|
116
|
+
elif avahi_379:
|
117
|
+
log_avahi_379((self.offset, pointer, len(self.data)))
|
118
|
+
label.extend(b"a")
|
119
|
+
break
|
99
120
|
else:
|
100
|
-
|
101
121
|
raise BufferError(
|
102
122
|
"Invalid pointer in DNSLabel [offset=%d,pointer=%d,length=%d]"
|
103
123
|
% (self.offset, pointer, len(self.data))
|
copyparty/svchub.py
CHANGED
@@ -783,7 +783,7 @@ class SvcHub(object):
|
|
783
783
|
al.exp_md = odfusion(exp, al.exp_md.replace(" ", ","))
|
784
784
|
al.exp_lg = odfusion(exp, al.exp_lg.replace(" ", ","))
|
785
785
|
|
786
|
-
for k in ["no_hash", "no_idx", "og_ua"]:
|
786
|
+
for k in ["no_hash", "no_idx", "og_ua", "srch_excl"]:
|
787
787
|
ptn = getattr(self.args, k)
|
788
788
|
if ptn:
|
789
789
|
setattr(self.args, k, re.compile(ptn))
|
copyparty/u2idx.py
CHANGED
@@ -318,7 +318,8 @@ class U2idx(object):
|
|
318
318
|
sort ,
|
319
319
|
lim ,
|
320
320
|
) :
|
321
|
-
|
321
|
+
dbg = self.args.srch_dbg
|
322
|
+
if dbg:
|
322
323
|
t = "searching across all %s volumes in which the user has 'r' (full read access):\n %s"
|
323
324
|
zs = "\n ".join(["/%s = %s" % (x.vpath, x.realpath) for x in vols])
|
324
325
|
self.log(t % (len(vols), zs), 5)
|
@@ -361,14 +362,14 @@ class U2idx(object):
|
|
361
362
|
if not cur:
|
362
363
|
continue
|
363
364
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
excl.append(vp2[len(vtop) :].lstrip("/"))
|
365
|
+
dots = flags.get("dotsrch") and uname in vol.axs.udot
|
366
|
+
zs = "srch_re_dots" if dots else "srch_re_nodot"
|
367
|
+
rex = flags.get(zs) # type: ignore
|
368
368
|
|
369
|
-
if
|
370
|
-
t = "searching in volume /%s (%s),
|
371
|
-
self.log(t % (vtop, ptop,
|
369
|
+
if dbg:
|
370
|
+
t = "searching in volume /%s (%s), excluding %s"
|
371
|
+
self.log(t % (vtop, ptop, rex.pattern), 5)
|
372
|
+
rex_cfg = flags.get("srch_excl")
|
372
373
|
|
373
374
|
self.active_cur = cur
|
374
375
|
|
@@ -381,7 +382,6 @@ class U2idx(object):
|
|
381
382
|
|
382
383
|
sret = []
|
383
384
|
fk = flags.get("fk")
|
384
|
-
dots = flags.get("dotsrch") and uname in vol.axs.udot
|
385
385
|
fk_alg = 2 if "fka" in flags else 1
|
386
386
|
c = cur.execute(uq, tuple(vuv))
|
387
387
|
for hit in c:
|
@@ -390,20 +390,23 @@ class U2idx(object):
|
|
390
390
|
if rd.startswith("//") or fn.startswith("//"):
|
391
391
|
rd, fn = s3dec(rd, fn)
|
392
392
|
|
393
|
-
|
394
|
-
if self.args.srch_dbg:
|
395
|
-
zs = vjoin(vjoin(vtop, rd), fn)
|
396
|
-
t = "database inconsistency in volume '/%s'; ignoring: %s"
|
397
|
-
self.log(t % (vtop, zs), 1)
|
398
|
-
continue
|
393
|
+
vp = vjoin(vjoin(vtop, rd), fn)
|
399
394
|
|
400
|
-
|
401
|
-
if not dots and "/." in ("/" + rp):
|
395
|
+
if vp in seen_rps:
|
402
396
|
continue
|
403
397
|
|
404
|
-
if
|
398
|
+
if rex.search(vp):
|
399
|
+
if dbg:
|
400
|
+
if rex_cfg and rex_cfg.search(vp): # type: ignore
|
401
|
+
self.log("filtered by srch_excl: %s" % (vp,), 6)
|
402
|
+
elif not dots and "/." in ("/" + vp):
|
403
|
+
pass
|
404
|
+
else:
|
405
|
+
t = "database inconsistency in volume '/%s'; ignoring: %s"
|
406
|
+
self.log(t % (vtop, vp), 1)
|
405
407
|
continue
|
406
408
|
|
409
|
+
rp = quotep(vp)
|
407
410
|
if not fk:
|
408
411
|
suf = ""
|
409
412
|
else:
|
@@ -425,7 +428,7 @@ class U2idx(object):
|
|
425
428
|
if lim < 0:
|
426
429
|
break
|
427
430
|
|
428
|
-
if
|
431
|
+
if dbg:
|
429
432
|
t = "in volume '/%s': hit: %s"
|
430
433
|
self.log(t % (vtop, rp), 5)
|
431
434
|
|
@@ -455,7 +458,7 @@ class U2idx(object):
|
|
455
458
|
ret.extend(sret)
|
456
459
|
# print("[{}] {}".format(ptop, sret))
|
457
460
|
|
458
|
-
if
|
461
|
+
if dbg:
|
459
462
|
t = "in volume '/%s': got %d hits, %d total so far"
|
460
463
|
self.log(t % (vtop, len(sret), len(ret)), 5)
|
461
464
|
|
copyparty/up2k.py
CHANGED
@@ -85,16 +85,23 @@ if TYPE_CHECKING:
|
|
85
85
|
zsg = "avif,avifs,bmp,gif,heic,heics,heif,heifs,ico,j2p,j2k,jp2,jpeg,jpg,jpx,png,tga,tif,tiff,webp"
|
86
86
|
CV_EXTS = set(zsg.split(","))
|
87
87
|
|
88
|
+
zsg = "nohash noidx xdev xvol"
|
89
|
+
VF_AFFECTS_INDEXING = set(zsg.split(" "))
|
90
|
+
|
88
91
|
|
89
92
|
SBUSY = "cannot receive uploads right now;\nserver busy with %s.\nPlease wait; the client will retry..."
|
90
93
|
|
91
94
|
HINT_HISTPATH = "you could try moving the database to another location (preferably an SSD or NVME drive) using either the --hist argument (global option for all volumes), or the hist volflag (just for this volume)"
|
92
95
|
|
93
96
|
|
97
|
+
NULLSTAT = os.stat_result((0, -1, -1, 0, 0, 0, 0, 0, 0, 0))
|
98
|
+
|
99
|
+
|
94
100
|
class Dbw(object):
|
95
|
-
def __init__(self, c , n , t ) :
|
101
|
+
def __init__(self, c , n , nf , t ) :
|
96
102
|
self.c = c
|
97
103
|
self.n = n
|
104
|
+
self.nf = nf
|
98
105
|
self.t = t
|
99
106
|
|
100
107
|
|
@@ -1067,7 +1074,8 @@ class Up2k(object):
|
|
1067
1074
|
ft = "\033[0;32m{}{:.0}"
|
1068
1075
|
ff = "\033[0;35m{}{:.0}"
|
1069
1076
|
fv = "\033[0;36m{}:\033[90m{}"
|
1070
|
-
|
1077
|
+
zs = "html_head mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot"
|
1078
|
+
fx = set(zs.split())
|
1071
1079
|
fd = vf_bmap()
|
1072
1080
|
fd.update(vf_cmap())
|
1073
1081
|
fd.update(vf_vmap())
|
@@ -1224,10 +1232,17 @@ class Up2k(object):
|
|
1224
1232
|
def _verify_db_cache(self, cur , vpath ) :
|
1225
1233
|
# check if list of intersecting volumes changed since last use; drop caches if so
|
1226
1234
|
prefix = (vpath + "/").lstrip("/")
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1235
|
+
vps = [x for x in self.vfs.all_vols if x.startswith(prefix)]
|
1236
|
+
vps.sort()
|
1237
|
+
seed = [x[len(prefix) :] for x in vps]
|
1238
|
+
|
1239
|
+
# also consider volflags which affect indexing
|
1240
|
+
for vp in vps:
|
1241
|
+
vf = self.vfs.all_vols[vp].flags
|
1242
|
+
vf = {k: v for k, v in vf.items() if k in VF_AFFECTS_INDEXING}
|
1243
|
+
seed.append(str(sorted(vf.items())))
|
1244
|
+
|
1245
|
+
zb = hashlib.sha1("\n".join(seed).encode("utf-8", "replace")).digest()
|
1231
1246
|
vcfg = ub64enc(zb[:18]).decode("ascii")
|
1232
1247
|
|
1233
1248
|
c = cur.execute("select v from kv where k = 'volcfg'")
|
@@ -1259,7 +1274,7 @@ class Up2k(object):
|
|
1259
1274
|
|
1260
1275
|
cur, db_path = reg
|
1261
1276
|
|
1262
|
-
db = Dbw(cur, 0, time.time())
|
1277
|
+
db = Dbw(cur, 0, 0, time.time())
|
1263
1278
|
self.pp.n = next(db.c.execute("select count(w) from up"))[0]
|
1264
1279
|
|
1265
1280
|
excl = [
|
@@ -1311,7 +1326,7 @@ class Up2k(object):
|
|
1311
1326
|
self.hub.log_stacks()
|
1312
1327
|
|
1313
1328
|
if db.n:
|
1314
|
-
self.log("commit
|
1329
|
+
self.log("commit %d new files; %d updates" % (db.nf, db.n))
|
1315
1330
|
|
1316
1331
|
if self.args.no_dhash:
|
1317
1332
|
if db.c.execute("select d from dh").fetchone():
|
@@ -1612,12 +1627,13 @@ class Up2k(object):
|
|
1612
1627
|
# skip upload hooks by not providing vflags
|
1613
1628
|
self.db_add(db.c, {}, rd, fn, lmod, sz, "", "", wark, wark, "", "", ip, at)
|
1614
1629
|
db.n += 1
|
1630
|
+
db.nf += 1
|
1615
1631
|
tfa += 1
|
1616
1632
|
td = time.time() - db.t
|
1617
1633
|
if db.n >= 4096 or td >= 60:
|
1618
|
-
self.log("commit
|
1634
|
+
self.log("commit %d new files; %d updates" % (db.nf, db.n))
|
1619
1635
|
db.c.connection.commit()
|
1620
|
-
db.n = 0
|
1636
|
+
db.n = db.nf = 0
|
1621
1637
|
db.t = time.time()
|
1622
1638
|
|
1623
1639
|
if not self.args.no_dhash:
|
@@ -1630,7 +1646,7 @@ class Up2k(object):
|
|
1630
1646
|
# drop shadowed folders
|
1631
1647
|
for sh_rd in unreg:
|
1632
1648
|
n = 0
|
1633
|
-
q = "select count(w) from up where (rd=? or rd like ?||'/%')
|
1649
|
+
q = "select count(w) from up where (rd=? or rd like ?||'/%')"
|
1634
1650
|
for sh_erd in [sh_rd, "//" + w8b64enc(sh_rd)]:
|
1635
1651
|
try:
|
1636
1652
|
erd_erd = (sh_erd, sh_erd)
|
@@ -1647,7 +1663,7 @@ class Up2k(object):
|
|
1647
1663
|
q = "delete from dh where (d = ? or d like ?||'/%')"
|
1648
1664
|
db.c.execute(q, erd_erd)
|
1649
1665
|
|
1650
|
-
q = "delete from up where (rd=? or rd like ?||'/%')
|
1666
|
+
q = "delete from up where (rd=? or rd like ?||'/%')"
|
1651
1667
|
db.c.execute(q, erd_erd)
|
1652
1668
|
tfa += n
|
1653
1669
|
|
@@ -2914,7 +2930,7 @@ class Up2k(object):
|
|
2914
2930
|
raise Exception()
|
2915
2931
|
except Exception as ex:
|
2916
2932
|
if n4g:
|
2917
|
-
st =
|
2933
|
+
st = NULLSTAT
|
2918
2934
|
else:
|
2919
2935
|
lost.append((cur, dp_dir, dp_fn))
|
2920
2936
|
continue
|
@@ -3061,7 +3077,8 @@ class Up2k(object):
|
|
3061
3077
|
if cur:
|
3062
3078
|
dupe = (cj["prel"], cj["name"], cj["lmod"])
|
3063
3079
|
try:
|
3064
|
-
self.dupesched[src]
|
3080
|
+
if dupe not in self.dupesched[src]:
|
3081
|
+
self.dupesched[src].append(dupe)
|
3065
3082
|
except:
|
3066
3083
|
self.dupesched[src] = [dupe]
|
3067
3084
|
|
@@ -4636,6 +4653,13 @@ class Up2k(object):
|
|
4636
4653
|
t = "forgetting partial upload {} ({})"
|
4637
4654
|
p = self._vis_job_progress(job)
|
4638
4655
|
self.log(t.format(wark, p))
|
4656
|
+
|
4657
|
+
src = djoin(ptop, vrem)
|
4658
|
+
zi = len(self.dupesched.pop(src, []))
|
4659
|
+
if zi:
|
4660
|
+
t = "...and forgetting %d links in dupesched"
|
4661
|
+
self.log(t % (zi,))
|
4662
|
+
|
4639
4663
|
assert wark
|
4640
4664
|
del reg[wark]
|
4641
4665
|
|
copyparty/util.py
CHANGED
@@ -2709,6 +2709,26 @@ def yieldfile(fn , bufsz ) :
|
|
2709
2709
|
yield buf
|
2710
2710
|
|
2711
2711
|
|
2712
|
+
def justcopy(
|
2713
|
+
fin ,
|
2714
|
+
fout ,
|
2715
|
+
hashobj ,
|
2716
|
+
max_sz ,
|
2717
|
+
slp ,
|
2718
|
+
) :
|
2719
|
+
tlen = 0
|
2720
|
+
for buf in fin:
|
2721
|
+
tlen += len(buf)
|
2722
|
+
if max_sz and tlen > max_sz:
|
2723
|
+
continue
|
2724
|
+
|
2725
|
+
fout.write(buf)
|
2726
|
+
if slp:
|
2727
|
+
time.sleep(slp)
|
2728
|
+
|
2729
|
+
return tlen, "checksum-disabled", "checksum-disabled"
|
2730
|
+
|
2731
|
+
|
2712
2732
|
def hashcopy(
|
2713
2733
|
fin ,
|
2714
2734
|
fout ,
|
@@ -3416,7 +3436,6 @@ def runhook(
|
|
3416
3436
|
at ,
|
3417
3437
|
txt ,
|
3418
3438
|
) :
|
3419
|
-
asrv = (broker or up2k).asrv
|
3420
3439
|
args = (broker or up2k).args
|
3421
3440
|
vp = vp.replace("\\", "/")
|
3422
3441
|
ret = {"rc": 0}
|
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 = "2024-
|
4
|
+
S_VERSION = "2.7"
|
5
|
+
S_BUILD_DT = "2024-12-06"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -1031,8 +1031,8 @@ class Ctl(object):
|
|
1031
1031
|
handshake(self.ar, file, False)
|
1032
1032
|
|
1033
1033
|
def _fancy(self):
|
1034
|
+
atexit.register(self.cleanup_vt100)
|
1034
1035
|
if VT100 and not self.ar.ns:
|
1035
|
-
atexit.register(self.cleanup_vt100)
|
1036
1036
|
ss.scroll_region(3)
|
1037
1037
|
|
1038
1038
|
Daemon(self.hasher)
|
@@ -1040,6 +1040,7 @@ class Ctl(object):
|
|
1040
1040
|
Daemon(self.handshaker)
|
1041
1041
|
Daemon(self.uploader)
|
1042
1042
|
|
1043
|
+
last_sp = -1
|
1043
1044
|
while True:
|
1044
1045
|
with self.exit_cond:
|
1045
1046
|
self.exit_cond.wait(0.07)
|
@@ -1078,6 +1079,12 @@ class Ctl(object):
|
|
1078
1079
|
else:
|
1079
1080
|
txt = " "
|
1080
1081
|
|
1082
|
+
if not VT100: # OSC9;4 (taskbar-progress)
|
1083
|
+
sp = int(self.up_b * 100 / self.nbytes) or 1
|
1084
|
+
if last_sp != sp:
|
1085
|
+
last_sp = sp
|
1086
|
+
txt += "\033]9;4;1;%d\033\\" % (sp,)
|
1087
|
+
|
1081
1088
|
if not self.up_br:
|
1082
1089
|
spd = self.hash_b / ((time.time() - self.t0) or 1)
|
1083
1090
|
eta = (self.nbytes - self.hash_b) / (spd or 1)
|
@@ -1095,6 +1102,8 @@ class Ctl(object):
|
|
1095
1102
|
tail = "\033[K\033[u" if VT100 and not self.ar.ns else "\r"
|
1096
1103
|
|
1097
1104
|
t = "%s eta @ %s/s, %s, %d# left\033[K" % (self.eta, spd, sleft, nleft)
|
1105
|
+
if not self.hash_b:
|
1106
|
+
t = " now hashing..."
|
1098
1107
|
eprint(txt + "\033]0;{0}\033\\\r{0}{1}".format(t, tail))
|
1099
1108
|
|
1100
1109
|
if self.ar.wlist:
|
@@ -1115,7 +1124,10 @@ class Ctl(object):
|
|
1115
1124
|
handshake(self.ar, file, False)
|
1116
1125
|
|
1117
1126
|
def cleanup_vt100(self):
|
1118
|
-
|
1127
|
+
if VT100:
|
1128
|
+
ss.scroll_region(None)
|
1129
|
+
else:
|
1130
|
+
eprint("\033]9;4;0\033\\")
|
1119
1131
|
eprint("\033[J\033]0;\033\\")
|
1120
1132
|
|
1121
1133
|
def cb_hasher(self, file, ofs):
|
@@ -1130,7 +1142,9 @@ class Ctl(object):
|
|
1130
1142
|
isdir = stat.S_ISDIR(inf.st_mode)
|
1131
1143
|
if self.ar.z or self.ar.drd:
|
1132
1144
|
rd = rel if isdir else os.path.dirname(rel)
|
1133
|
-
srd = rd.decode("utf-8", "replace").replace("\\", "/")
|
1145
|
+
srd = rd.decode("utf-8", "replace").replace("\\", "/").rstrip("/")
|
1146
|
+
if srd:
|
1147
|
+
srd += "/"
|
1134
1148
|
if prd != rd:
|
1135
1149
|
prd = rd
|
1136
1150
|
ls = {}
|
@@ -1165,11 +1179,11 @@ class Ctl(object):
|
|
1165
1179
|
bnames = [x for x in ls if x not in lnodes and x != b".hist"]
|
1166
1180
|
vpath = self.ar.url.split("://")[-1].split("/", 1)[-1]
|
1167
1181
|
names = [x.decode("utf-8", WTF8) for x in bnames]
|
1168
|
-
locs = [vpath + srd +
|
1182
|
+
locs = [vpath + srd + x for x in names]
|
1169
1183
|
while locs:
|
1170
1184
|
req = locs
|
1171
1185
|
while req:
|
1172
|
-
print("DELETING ~%s
|
1186
|
+
print("DELETING ~%s#%s" % (srd, len(req)))
|
1173
1187
|
body = json.dumps(req).encode("utf-8")
|
1174
1188
|
sc, txt = web.req(
|
1175
1189
|
"POST", self.ar.url + "?delete", {}, body, MJ
|
@@ -1534,6 +1548,38 @@ source file/folder selection uses rsync syntax, meaning that:
|
|
1534
1548
|
except:
|
1535
1549
|
pass
|
1536
1550
|
|
1551
|
+
# msys2 doesn't uncygpath absolute paths with whitespace
|
1552
|
+
if not VT100:
|
1553
|
+
zsl = []
|
1554
|
+
for fn in ar.files:
|
1555
|
+
if re.search("^/[a-z]/", fn):
|
1556
|
+
fn = r"%s:\%s" % (fn[1:2], fn[3:])
|
1557
|
+
zsl.append(fn.replace("/", "\\"))
|
1558
|
+
ar.files = zsl
|
1559
|
+
|
1560
|
+
fok = []
|
1561
|
+
fng = []
|
1562
|
+
for fn in ar.files:
|
1563
|
+
if os.path.exists(fn):
|
1564
|
+
fok.append(fn)
|
1565
|
+
elif VT100:
|
1566
|
+
fng.append(fn)
|
1567
|
+
else:
|
1568
|
+
# windows leaves glob-expansion to the invoked process... okayyy let's get to work
|
1569
|
+
from glob import glob
|
1570
|
+
|
1571
|
+
fns = glob(fn)
|
1572
|
+
if fns:
|
1573
|
+
fok.extend(fns)
|
1574
|
+
else:
|
1575
|
+
fng.append(fn)
|
1576
|
+
|
1577
|
+
if fng:
|
1578
|
+
t = "some files/folders were not found:\n %s"
|
1579
|
+
raise Exception(t % ("\n ".join(fng),))
|
1580
|
+
|
1581
|
+
ar.files = fok
|
1582
|
+
|
1537
1583
|
if ar.drd:
|
1538
1584
|
ar.dr = True
|
1539
1585
|
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/deps/easymde.js.gz
CHANGED
Binary file
|
copyparty/web/deps/marked.js.gz
CHANGED
Binary file
|
Binary file
|
copyparty/web/md.js.gz
CHANGED
Binary file
|
copyparty/web/md2.js.gz
CHANGED
Binary file
|
copyparty/web/up2k.js.gz
CHANGED
Binary file
|
copyparty/web/util.js.gz
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.4
|
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
|
@@ -1152,11 +1152,12 @@ using the GUI (winXP or later):
|
|
1152
1152
|
* on winXP only, click the `Sign up for online storage` hyperlink instead and put the URL there
|
1153
1153
|
* providing your password as the username is recommended; the password field can be anything or empty
|
1154
1154
|
|
1155
|
-
|
1155
|
+
the webdav client that's built into windows has the following list of bugs; you can avoid all of these by connecting with rclone instead:
|
1156
1156
|
* win7+ doesn't actually send the password to the server when reauthenticating after a reboot unless you first try to login with an incorrect password and then switch to the correct password
|
1157
1157
|
* or just type your password into the username field instead to get around it entirely
|
1158
1158
|
* connecting to a folder which allows anonymous read will make writing impossible, as windows has decided it doesn't need to login
|
1159
1159
|
* workaround: connect twice; first to a folder which requires auth, then to the folder you actually want, and leave both of those mounted
|
1160
|
+
* or set the server-option `--dav-auth` to force password-auth for all webdav clients
|
1160
1161
|
* win7+ may open a new tcp connection for every file and sometimes forgets to close them, eventually needing a reboot
|
1161
1162
|
* maybe NIC-related (??), happens with win10-ltsc on e1000e but not virtio
|
1162
1163
|
* windows cannot access folders which contain filenames with invalid unicode or forbidden characters (`<>:"/\|?*`), or names ending with `.`
|
@@ -1323,7 +1324,7 @@ note:
|
|
1323
1324
|
|
1324
1325
|
### exclude-patterns
|
1325
1326
|
|
1326
|
-
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash \.iso
|
1327
|
+
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash '\.iso$'` or the volflag `:c,nohash=\.iso$`, this has the following consequences:
|
1327
1328
|
* initial indexing is way faster, especially when the volume is on a network disk
|
1328
1329
|
* makes it impossible to [file-search](#file-search)
|
1329
1330
|
* if someone uploads the same file contents, the upload will not be detected as a dupe, so it will not get symlinked or rejected
|
@@ -1334,6 +1335,8 @@ similarly, you can fully ignore files/folders using `--no-idx [...]` and `:c,noi
|
|
1334
1335
|
|
1335
1336
|
if you set `--no-hash [...]` globally, you can enable hashing for specific volumes using flag `:c,nohash=`
|
1336
1337
|
|
1338
|
+
to exclude certain filepaths from search-results, use `--srch-excl` or volflag `srch_excl` instead of `--no-idx`, for example `--srch-excl 'password|logs/[0-9]'`
|
1339
|
+
|
1337
1340
|
### filesystem guards
|
1338
1341
|
|
1339
1342
|
avoid traversing into other filesystems using `--xdev` / volflag `:c,xdev`, skipping any symlinks or bind-mounts to another HDD for example
|
@@ -1,21 +1,21 @@
|
|
1
1
|
copyparty/__init__.py,sha256=iRCNvMPg6k9WG_O2uCtlkD4vWogH8EgP9elp9XwSIJs,2610
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=fA4D0yAs6twyBcawN9lM7CtHuFagTsQloljWX9MZ1j0,113240
|
3
|
+
copyparty/__version__.py,sha256=PSHPFmB4WReQ90GVjo2tS3ZE1I6F3Z2igIEoAOtf4ZQ,251
|
4
|
+
copyparty/authsrv.py,sha256=CIK5OKl38LehdAt4hidCMpsATdJhPABJPkJStpQpp9U,103405
|
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=
|
10
|
+
copyparty/cfg.py,sha256=UUmFpFbTm750Nv9RnofS80-FTpWT37EggEtmkE1wbxE,10374
|
11
11
|
copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
|
12
12
|
copyparty/fsutil.py,sha256=5CshJWO7CflfaRRNOb3JxghUH7W5rmS_HWNmKfx42MM,4538
|
13
13
|
copyparty/ftpd.py,sha256=T97SFS7JFtvRLbJX8C4fJSYwe13vhN3-E6emtlVmqLA,17608
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=hwHJ8EwV30MHZ6hGPGfmCuow5Nu2daMV2EN7Ups5jb8,207704
|
15
15
|
copyparty/httpconn.py,sha256=mQSgljh0Q-jyWjF4tQLrHbRKRe9WKl19kGqsGMsJpWo,6880
|
16
16
|
copyparty/httpsrv.py,sha256=PXLZlT6iuJZYG9ajNsAaNgRK3UtS4CrOGFGXOpkRtOk,18235
|
17
17
|
copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
|
18
|
-
copyparty/mdns.py,sha256=
|
18
|
+
copyparty/mdns.py,sha256=G73OWWg1copda47LgayCRK7qjVrk6cnUGpMR5ugmi7o,18315
|
19
19
|
copyparty/metrics.py,sha256=EOIiPOItEQmdK9YgNb75l0kCzanWb6RtJGwMI7ufifY,8966
|
20
20
|
copyparty/mtag.py,sha256=o-rxu4LajWF4H3HFmfCbXnKfs0GCQh1FQ0XywuW6wOc,19934
|
21
21
|
copyparty/multicast.py,sha256=Ha27l2oATEa-Qo2WOzkeRgjAm6G_YDCfbVJWR-ao2UE,12319
|
@@ -24,19 +24,19 @@ copyparty/smbd.py,sha256=Or7RF13cl1r3ncnpVh8BqyAGqH2Oa04O9iPZWCoB0Bo,14609
|
|
24
24
|
copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
|
25
25
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
26
26
|
copyparty/sutil.py,sha256=JTMrQwcWH85hXB_cKG206eDZ967WZDGaP00AWvl_gB0,3214
|
27
|
-
copyparty/svchub.py,sha256=
|
27
|
+
copyparty/svchub.py,sha256=sAHkiPGzzKACLqKlem2V-bps9Xh-wHlcfwaNywxcd5A,40877
|
28
28
|
copyparty/szip.py,sha256=HFtnwOiBgx0HMLUf-h_T84zSlRijPxmhRo5PM613kRA,8602
|
29
29
|
copyparty/tcpsrv.py,sha256=VuW_aVDcyXIhIMZ8I-wpIouX8MI9TGp7KKSRohrMTtk,19897
|
30
30
|
copyparty/tftpd.py,sha256=FRCALO3PigoBlwUrqxoKHM_xk7wT2O0GPG1TvNRtjOY,13606
|
31
31
|
copyparty/th_cli.py,sha256=o6FMkerYvAXS455z3DUossVztu_nzFlYSQhs6qN6Jt8,4636
|
32
32
|
copyparty/th_srv.py,sha256=LBcB4LpsF-H7L52Z0Dhn9LogRjJVPp1GKa8MeIMIBnw,29596
|
33
|
-
copyparty/u2idx.py,sha256=
|
34
|
-
copyparty/up2k.py,sha256=
|
35
|
-
copyparty/util.py,sha256=
|
33
|
+
copyparty/u2idx.py,sha256=kF4TE-j78Faq_f4vGh5So5raYDYLt2UDpza6yBA3f54,13687
|
34
|
+
copyparty/up2k.py,sha256=KQZcpqWRwjvmJLFEo3ejVWDroQi10jQdvgxuASDpUlY,174476
|
35
|
+
copyparty/util.py,sha256=UyaYXfVO4nOkqhSMi9SZn2zK2W9texb9CL9rsqMak8I,95135
|
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
|
39
|
-
copyparty/res/COPYING.txt,sha256=
|
39
|
+
copyparty/res/COPYING.txt,sha256=1LnBxkwJuC8mRBxuoMF2UIcpCjcteIzFHotSUE1Xte0,9776
|
40
40
|
copyparty/res/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
copyparty/res/insecure.pem,sha256=FEt7jgrn6ZHTlFopq_LFAN027YIoaHi0HQFBbzYnEwc,2876
|
42
42
|
copyparty/stolen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -46,8 +46,8 @@ copyparty/stolen/dnslib/__init__.py,sha256=SmYdaHdL5czxKxrOFGvzbfmojOthRky1GXKgm
|
|
46
46
|
copyparty/stolen/dnslib/bimap.py,sha256=j_ah40P3kOw0AQT5vvMcv7XbMtS0jV6Oe9YGCh7J57s,1182
|
47
47
|
copyparty/stolen/dnslib/bit.py,sha256=uDECHT5wM-QObxxRgc4lJq9CUcd7hglRLgs0K1X8mnU,348
|
48
48
|
copyparty/stolen/dnslib/buffer.py,sha256=bvj9rTn4EcccVuMWe1b5j57ex6elba3NCDBdevsnoSc,1407
|
49
|
-
copyparty/stolen/dnslib/dns.py,sha256=
|
50
|
-
copyparty/stolen/dnslib/label.py,sha256=
|
49
|
+
copyparty/stolen/dnslib/dns.py,sha256=wEaStjfDhT2RI6lS6StwDrkS40afGnbHPue1duOT3vs,21020
|
50
|
+
copyparty/stolen/dnslib/label.py,sha256=GKN4JkmZPdsHIyt70oFQYb4KB4Muh2zvGvla-6HiMQ0,5536
|
51
51
|
copyparty/stolen/dnslib/lex.py,sha256=XuXvz4PHzSaEdRRl8xnYaM8cAupzns0QW3oeFn-4isM,2615
|
52
52
|
copyparty/stolen/dnslib/ranges.py,sha256=XqR6NaRMm0xiEht590KhOjKjIuUFgW4I9_zPmPsGV0c,1810
|
53
53
|
copyparty/stolen/ifaddr/__init__.py,sha256=vpREjAyPubr5s1NJi91icXV3q1o4DrKAvHABwkoeJB0,706
|
@@ -55,17 +55,17 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
|
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=_amC3ipOrXKEFz8DsVP-JEl49VjMQYiKyF78eWfG-uk,7965
|
58
|
-
copyparty/web/browser.css.gz,sha256=
|
58
|
+
copyparty/web/browser.css.gz,sha256=kurx_iA-KxLYx8PqJsn0bJVjkAxP-0YTOHSV9l_oouo,11645
|
59
59
|
copyparty/web/browser.html,sha256=KCkZ_LwzQnj9xhXKYptAxp6W3nVGiDoSJ4ioZDo7rQ0,4827
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=7YbcHLByMAc71j3nKKUrCEExAzfenYnHPBSrnJ8iJFA,89833
|
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
|
64
64
|
copyparty/web/md.css.gz,sha256=UZpN0J7ubVM05CZkbZYkQRJeGgJt_GNDEzKTGSQd8h4,2032
|
65
65
|
copyparty/web/md.html,sha256=isNbIzWbp_oqkhQSXm0uf3st3h4uB3LLTXFcHHcvgPQ,4189
|
66
|
-
copyparty/web/md.js.gz,sha256=
|
66
|
+
copyparty/web/md.js.gz,sha256=tw9vS9yZzyVW4FNOTv0MMHBdBEedfahZRZ8WhVJDu4A,4180
|
67
67
|
copyparty/web/md2.css.gz,sha256=uIVHKScThdbcfhXNSHgKZnALYpxbnXC-WuEzOJ20Lpc,699
|
68
|
-
copyparty/web/md2.js.gz,sha256=
|
68
|
+
copyparty/web/md2.js.gz,sha256=w0Ve06BUcyZfcWR8DAPpCj-kI-uL_wTL2aX_0PsNc-I,8363
|
69
69
|
copyparty/web/mde.css.gz,sha256=2SkAEDKIRPqywNJ8t_heQaeBQ_R73Rf-pQI_bDoKF6o,942
|
70
70
|
copyparty/web/mde.html,sha256=ImBhQAaEUCke2M85QU_fl4X2XQExRLcEzgCEN8RNe9o,1759
|
71
71
|
copyparty/web/mde.js.gz,sha256=kN2eUSvr4mFuksfK4-4LimJmWdwsao39Sea2lWtu8L0,2224
|
@@ -80,12 +80,12 @@ copyparty/web/splash.js.gz,sha256=EEfsi9YGtPTYRB6MPX8Dfg4YyfqncI9ldJS7_MGVOhs,27
|
|
80
80
|
copyparty/web/svcs.html,sha256=P5YZimYLeQMT0uz6u3clQSNZRc5Zs0Ok-ffcbcGSYuc,11762
|
81
81
|
copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
|
82
82
|
copyparty/web/ui.css.gz,sha256=v8U-1tetZzuzTpITjq8NWj1gg3jEiYDIIE8aE0dx63k,2800
|
83
|
-
copyparty/web/up2k.js.gz,sha256=
|
84
|
-
copyparty/web/util.js.gz,sha256=
|
83
|
+
copyparty/web/up2k.js.gz,sha256=vB3hLpRZzVStcN2-NAGjFdfroxFPbFvKss4vxVYyy1c,23371
|
84
|
+
copyparty/web/util.js.gz,sha256=MMDIZbxzBwBYE5eYLzhGGpC7h257oEFZaBKZwJ4uhc8,15077
|
85
85
|
copyparty/web/w.hash.js.gz,sha256=l3GpSJD6mcU-1CRWkIj7PybgbjlfSr8oeO3vortIrQk,1105
|
86
86
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
87
87
|
copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
|
88
|
-
copyparty/web/a/u2c.py,sha256=
|
88
|
+
copyparty/web/a/u2c.py,sha256=1XcH5XfC2UuGrpTnLVHCe4KFU0Vl6uC02CZz04rvKOc,51612
|
89
89
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
90
90
|
copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
|
91
91
|
copyparty/web/dd/3.png,sha256=4lho8Koz5tV7jJ4ODo6GMTScZfkqsT05yp48EDFIlyg,252
|
@@ -95,9 +95,9 @@ copyparty/web/dd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
95
95
|
copyparty/web/deps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
96
96
|
copyparty/web/deps/busy.mp3.gz,sha256=EVphk1_HYyRKJmtpeK99vbAstF7ub1f9ndu020H8PQ8,106
|
97
97
|
copyparty/web/deps/easymde.css.gz,sha256=vWxfueI64rPikuqFj69wJBtGisqf93AheQtOZqgUI_c,3041
|
98
|
-
copyparty/web/deps/easymde.js.gz,sha256=
|
98
|
+
copyparty/web/deps/easymde.js.gz,sha256=rHBs4XWQe2bmv7ZzDIk43oxnTwrwpq5laYHhV5sKQQo,77014
|
99
99
|
copyparty/web/deps/fuse.py,sha256=6j4Zy3VpQg629pwwIW77v2LJ1hy-qlyrxwhXfKl9B7I,33426
|
100
|
-
copyparty/web/deps/marked.js.gz,sha256=
|
100
|
+
copyparty/web/deps/marked.js.gz,sha256=3sviQ05gVpZF2s43evtFQZZSMSHV6K3OsS15OoBqb10,22610
|
101
101
|
copyparty/web/deps/mini-fa.css.gz,sha256=CTPrNaH8OTVmxajrGP88E2MkjadY9_81TBVnd9sw9Y8,572
|
102
102
|
copyparty/web/deps/mini-fa.woff,sha256=L9DNncV2TIyvsrspMbJouvnnt7F068Hbn7YZYvN76AU,2784
|
103
103
|
copyparty/web/deps/prism.css.gz,sha256=Z_A6rJ3MN5KWnjvXaV787aTW_5DT-xjFd0YZ7_W-Krk,1468
|
@@ -105,10 +105,10 @@ copyparty/web/deps/prism.js.gz,sha256=DR0OAfTUb6PkzSPgxjnjj7jqlpvuCHdMDJKbsQP7s5
|
|
105
105
|
copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cVCO0,1637
|
106
106
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
107
107
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
108
|
-
copyparty/web/deps/sha512.hw.js.gz,sha256=
|
109
|
-
copyparty-1.16.
|
110
|
-
copyparty-1.16.
|
111
|
-
copyparty-1.16.
|
112
|
-
copyparty-1.16.
|
113
|
-
copyparty-1.16.
|
114
|
-
copyparty-1.16.
|
108
|
+
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
109
|
+
copyparty-1.16.4.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
110
|
+
copyparty-1.16.4.dist-info/METADATA,sha256=yo6iBPRZrSl4VBK6h32czwBccoFewYTRoSFVaOOYr5s,140656
|
111
|
+
copyparty-1.16.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
112
|
+
copyparty-1.16.4.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
113
|
+
copyparty-1.16.4.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
114
|
+
copyparty-1.16.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|