copyparty 1.16.1__py3-none-any.whl → 1.16.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copyparty/__main__.py +6 -1
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +83 -0
- copyparty/cfg.py +3 -0
- copyparty/httpcli.py +108 -66
- copyparty/httpsrv.py +1 -1
- copyparty/mdns.py +7 -0
- copyparty/res/COPYING.txt +23 -30
- copyparty/stolen/dnslib/dns.py +2 -2
- copyparty/stolen/dnslib/label.py +21 -1
- copyparty/svchub.py +1 -1
- copyparty/u2idx.py +32 -20
- copyparty/up2k.py +34 -13
- copyparty/util.py +42 -6
- copyparty/web/a/u2c.py +7 -3
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.html +2 -3
- 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/shares.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/ui.css.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.dist-info}/METADATA +13 -10
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.dist-info}/RECORD +35 -35
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.dist-info}/WHEEL +1 -1
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.dist-info}/LICENSE +0 -0
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.dist-info}/entry_points.txt +0 -0
- {copyparty-1.16.1.dist-info → copyparty-1.16.3.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
|
|
@@ -1449,6 +1452,8 @@ def add_ui(ap, retry):
|
|
1449
1452
|
ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
|
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)")
|
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)")
|
1452
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)")
|
1453
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")
|
1454
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
@@ -360,6 +360,8 @@ class VFS(object):
|
|
360
360
|
self.ahtml = {}
|
361
361
|
self.aadmin = {}
|
362
362
|
self.adot = {}
|
363
|
+
self.js_ls = {}
|
364
|
+
self.js_htm = ""
|
363
365
|
|
364
366
|
if realpath:
|
365
367
|
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
@@ -1871,6 +1873,7 @@ class AuthSrv(object):
|
|
1871
1873
|
["no_hash", "nohash"],
|
1872
1874
|
["no_idx", "noidx"],
|
1873
1875
|
["og_ua", "og_ua"],
|
1876
|
+
["srch_excl", "srch_excl"],
|
1874
1877
|
]:
|
1875
1878
|
if vf in vol.flags:
|
1876
1879
|
ptn = re.compile(vol.flags.pop(vf))
|
@@ -2077,6 +2080,22 @@ class AuthSrv(object):
|
|
2077
2080
|
self.log(t.format(mtp), 1)
|
2078
2081
|
errors = True
|
2079
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
|
+
|
2080
2099
|
have_daw = False
|
2081
2100
|
for vol in vfs.all_nodes.values():
|
2082
2101
|
daw = vol.flags.get("daw") or self.args.daw
|
@@ -2297,6 +2316,70 @@ class AuthSrv(object):
|
|
2297
2316
|
cur.close()
|
2298
2317
|
db.close()
|
2299
2318
|
|
2319
|
+
self.js_ls = {}
|
2320
|
+
self.js_htm = {}
|
2321
|
+
for vn in self.vfs.all_nodes.values():
|
2322
|
+
vf = vn.flags
|
2323
|
+
vn.js_ls = {
|
2324
|
+
"idx": "e2d" in vf,
|
2325
|
+
"itag": "e2t" in vf,
|
2326
|
+
"dnsort": "nsort" in vf,
|
2327
|
+
"dhsortn": vf["hsortn"],
|
2328
|
+
"dsort": vf["sort"],
|
2329
|
+
"dcrop": vf["crop"],
|
2330
|
+
"dth3x": vf["th3x"],
|
2331
|
+
"u2ts": vf["u2ts"],
|
2332
|
+
"frand": bool(vf.get("rand")),
|
2333
|
+
"lifetime": vf.get("lifetime") or 0,
|
2334
|
+
"unlist": vf.get("unlist") or "",
|
2335
|
+
}
|
2336
|
+
js_htm = {
|
2337
|
+
"s_name": self.args.bname,
|
2338
|
+
"have_up2k_idx": "e2d" in vf,
|
2339
|
+
"have_acode": not self.args.no_acode,
|
2340
|
+
"have_shr": self.args.shr,
|
2341
|
+
"have_zip": not self.args.no_zip,
|
2342
|
+
"have_mv": not self.args.no_mv,
|
2343
|
+
"have_del": not self.args.no_del,
|
2344
|
+
"have_unpost": int(self.args.unpost),
|
2345
|
+
"have_emp": self.args.emp,
|
2346
|
+
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
2347
|
+
"txt_ext": self.args.textfiles.replace(",", " "),
|
2348
|
+
"def_hcols": list(vf.get("mth") or []),
|
2349
|
+
"unlist0": vf.get("unlist") or "",
|
2350
|
+
"dgrid": "grid" in vf,
|
2351
|
+
"dgsel": "gsel" in vf,
|
2352
|
+
"dnsort": "nsort" in vf,
|
2353
|
+
"dhsortn": vf["hsortn"],
|
2354
|
+
"dsort": vf["sort"],
|
2355
|
+
"dcrop": vf["crop"],
|
2356
|
+
"dth3x": vf["th3x"],
|
2357
|
+
"dvol": self.args.au_vol,
|
2358
|
+
"idxh": int(self.args.ih),
|
2359
|
+
"themes": self.args.themes,
|
2360
|
+
"turbolvl": self.args.turbo,
|
2361
|
+
"u2j": self.args.u2j,
|
2362
|
+
"u2sz": self.args.u2sz,
|
2363
|
+
"u2ts": vf["u2ts"],
|
2364
|
+
"frand": bool(vf.get("rand")),
|
2365
|
+
"lifetime": vn.js_ls["lifetime"],
|
2366
|
+
"u2sort": self.args.u2sort,
|
2367
|
+
}
|
2368
|
+
vn.js_htm = json.dumps(js_htm)
|
2369
|
+
|
2370
|
+
vols = list(vfs.all_nodes.values())
|
2371
|
+
if enshare:
|
2372
|
+
vols.append(shv)
|
2373
|
+
vols.extend(list(shv.nodes.values()))
|
2374
|
+
|
2375
|
+
for vol in vols:
|
2376
|
+
dbv = vol.get_dbv("")[0]
|
2377
|
+
vol.js_ls = vol.js_ls or dbv.js_ls or {}
|
2378
|
+
vol.js_htm = vol.js_htm or dbv.js_htm or "{}"
|
2379
|
+
|
2380
|
+
zs = str(vol.flags.get("tcolor") or self.args.tcolor)
|
2381
|
+
vol.flags["tcolor"] = zs.lstrip("#")
|
2382
|
+
|
2300
2383
|
def load_sessions(self, quiet=False) :
|
2301
2384
|
# mutex me
|
2302
2385
|
if self.args.no_ses:
|
copyparty/cfg.py
CHANGED
@@ -42,6 +42,7 @@ def vf_bmap() :
|
|
42
42
|
"magic",
|
43
43
|
"no_sb_md",
|
44
44
|
"no_sb_lg",
|
45
|
+
"nsort",
|
45
46
|
"og",
|
46
47
|
"og_no_head",
|
47
48
|
"og_s_title",
|
@@ -69,6 +70,7 @@ def vf_vmap() :
|
|
69
70
|
}
|
70
71
|
for k in (
|
71
72
|
"dbd",
|
73
|
+
"hsortn",
|
72
74
|
"html_head",
|
73
75
|
"lg_sbf",
|
74
76
|
"md_sbf",
|
@@ -190,6 +192,7 @@ flagcats = {
|
|
190
192
|
"xvol": "do not follow symlinks leaving the volume root",
|
191
193
|
"dotsrch": "show dotfiles in search results",
|
192
194
|
"nodotsrch": "hide dotfiles in search results (default)",
|
195
|
+
"srch_excl": "exclude search results with URL matching this regex",
|
193
196
|
},
|
194
197
|
'database, audio tags\n"mte", "mth", "mtp", "mtm" all work the same as -mte, -mth, ...': {
|
195
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
|
"""
|
@@ -243,7 +251,6 @@ class HttpCli(object):
|
|
243
251
|
ka["ts"] = self.conn.hsrv.cachebuster()
|
244
252
|
ka["lang"] = self.args.lang
|
245
253
|
ka["favico"] = self.args.favico
|
246
|
-
ka["s_name"] = self.args.bname
|
247
254
|
ka["s_doctitle"] = self.args.doctitle
|
248
255
|
ka["tcolor"] = self.vn.flags["tcolor"]
|
249
256
|
|
@@ -700,7 +707,7 @@ class HttpCli(object):
|
|
700
707
|
|
701
708
|
if pex.code != 404 or self.do_log:
|
702
709
|
self.log(
|
703
|
-
"%s\033[0m, %s" % (msg, self.vpath),
|
710
|
+
"http%d: %s\033[0m, %s" % (pex.code, msg, self.vpath),
|
704
711
|
6 if em.startswith("client d/c ") else 3,
|
705
712
|
)
|
706
713
|
|
@@ -1239,7 +1246,7 @@ class HttpCli(object):
|
|
1239
1246
|
self.log("RSS %s @%s" % (self.req, self.uname))
|
1240
1247
|
|
1241
1248
|
if not self.can_read:
|
1242
|
-
return self.tx_404()
|
1249
|
+
return self.tx_404(True)
|
1243
1250
|
|
1244
1251
|
vn = self.vn
|
1245
1252
|
if not vn.flags.get("rss"):
|
@@ -1409,17 +1416,19 @@ class HttpCli(object):
|
|
1409
1416
|
vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
|
1410
1417
|
|
1411
1418
|
try:
|
1412
|
-
|
1419
|
+
st = bos.stat(tap)
|
1413
1420
|
except OSError as ex:
|
1414
1421
|
if ex.errno not in (errno.ENOENT, errno.ENOTDIR):
|
1415
1422
|
raise
|
1416
1423
|
raise Pebkac(404)
|
1417
1424
|
|
1425
|
+
topdir = {"vp": "", "st": st}
|
1418
1426
|
fgen = []
|
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)
|
@@ -1450,6 +1459,12 @@ class HttpCli(object):
|
|
1450
1459
|
wrap=False,
|
1451
1460
|
)
|
1452
1461
|
|
1462
|
+
elif depth == "0" or not stat.S_ISDIR(st.st_mode):
|
1463
|
+
# propfind on a file; return as topdir
|
1464
|
+
if not self.can_read and not self.can_get:
|
1465
|
+
self.log("inaccessible: [%s]" % (self.vpath,))
|
1466
|
+
raise Pebkac(401, "authenticate")
|
1467
|
+
|
1453
1468
|
elif depth == "1":
|
1454
1469
|
_, vfs_ls, vfs_virt = vn.ls(
|
1455
1470
|
rem,
|
@@ -1468,15 +1483,12 @@ class HttpCli(object):
|
|
1468
1483
|
fgen = [{"vp": vp, "st": st} for vp, st in vfs_ls]
|
1469
1484
|
fgen += [{"vp": v, "st": vst} for v in vfs_virt]
|
1470
1485
|
|
1471
|
-
elif depth == "0":
|
1472
|
-
pass
|
1473
|
-
|
1474
1486
|
else:
|
1475
1487
|
t = "invalid depth value '{}' (must be either '0' or '1'{})"
|
1476
1488
|
t2 = " or 'infinity'" if self.args.dav_inf else ""
|
1477
1489
|
raise Pebkac(412, t.format(depth, t2))
|
1478
1490
|
|
1479
|
-
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:
|
1480
1492
|
self.log("inaccessible: [%s]" % (self.vpath,))
|
1481
1493
|
raise Pebkac(401, "authenticate")
|
1482
1494
|
|
@@ -1755,7 +1767,7 @@ class HttpCli(object):
|
|
1755
1767
|
|
1756
1768
|
if not self.can_write:
|
1757
1769
|
t = "user %s does not have write-access under /%s"
|
1758
|
-
raise Pebkac(403, t % (self.uname, self.vn.vpath))
|
1770
|
+
raise Pebkac(403 if self.pw else 401, t % (self.uname, self.vn.vpath))
|
1759
1771
|
|
1760
1772
|
if not self.args.no_dav and self._applesan():
|
1761
1773
|
return self.headers.get("content-length") == "0"
|
@@ -2046,10 +2058,31 @@ class HttpCli(object):
|
|
2046
2058
|
# small toctou, but better than clobbering a hardlink
|
2047
2059
|
wunlink(self.log, path, vfs.flags)
|
2048
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
|
+
|
2049
2082
|
f, fn = ren_open(fn, *open_a, **params)
|
2050
2083
|
try:
|
2051
2084
|
path = os.path.join(fdir, fn)
|
2052
|
-
post_sz, sha_hex, sha_b64 =
|
2085
|
+
post_sz, sha_hex, sha_b64 = copier(reader, f, hasher, 0, self.args.s_wr_slp)
|
2053
2086
|
finally:
|
2054
2087
|
f.close()
|
2055
2088
|
|
@@ -2286,8 +2319,8 @@ class HttpCli(object):
|
|
2286
2319
|
# kinda silly but has the least side effects
|
2287
2320
|
return self.handle_new_md()
|
2288
2321
|
|
2289
|
-
if act
|
2290
|
-
return self.handle_plain_upload(file0)
|
2322
|
+
if act in ("bput", "uput"):
|
2323
|
+
return self.handle_plain_upload(file0, act == "uput")
|
2291
2324
|
|
2292
2325
|
if act == "tput":
|
2293
2326
|
return self.handle_text_upload()
|
@@ -2898,13 +2931,41 @@ class HttpCli(object):
|
|
2898
2931
|
)
|
2899
2932
|
|
2900
2933
|
def handle_plain_upload(
|
2901
|
-
self,
|
2934
|
+
self,
|
2935
|
+
file0 ,
|
2936
|
+
nohash ,
|
2902
2937
|
) :
|
2903
2938
|
assert self.parser
|
2904
2939
|
nullwrite = self.args.nw
|
2905
2940
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2906
2941
|
self._assert_safe_rem(rem)
|
2907
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
|
+
|
2908
2969
|
upload_vpath = self.vpath
|
2909
2970
|
lim = vfs.get_dbv(rem)[0].lim
|
2910
2971
|
fdir_base = vfs.canonical(rem)
|
@@ -3034,8 +3095,8 @@ class HttpCli(object):
|
|
3034
3095
|
try:
|
3035
3096
|
tabspath = os.path.join(fdir, tnam)
|
3036
3097
|
self.log("writing to {}".format(tabspath))
|
3037
|
-
sz, sha_hex, sha_b64 =
|
3038
|
-
p_data, f,
|
3098
|
+
sz, sha_hex, sha_b64 = copier(
|
3099
|
+
p_data, f, hasher, max_sz, self.args.s_wr_slp
|
3039
3100
|
)
|
3040
3101
|
if sz == 0:
|
3041
3102
|
raise Pebkac(400, "empty files in post")
|
@@ -3167,10 +3228,15 @@ class HttpCli(object):
|
|
3167
3228
|
jmsg["error"] = errmsg
|
3168
3229
|
errmsg = "ERROR: " + errmsg
|
3169
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
|
+
|
3170
3236
|
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
3171
3237
|
vsuf = ""
|
3172
3238
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
3173
|
-
st = bos.stat(ap)
|
3239
|
+
st = A_FILE if nullwrite else bos.stat(ap)
|
3174
3240
|
alg = 2 if "fka" in vfs.flags else 1
|
3175
3241
|
vsuf = "?k=" + self.gen_fk(
|
3176
3242
|
alg,
|
@@ -3185,7 +3251,8 @@ class HttpCli(object):
|
|
3185
3251
|
|
3186
3252
|
vpath = "{}/{}".format(upload_vpath, lfn).strip("/")
|
3187
3253
|
rel_url = quotep(self.args.RS + vpath) + vsuf
|
3188
|
-
msg +=
|
3254
|
+
msg += file_fmt.format(
|
3255
|
+
halg,
|
3189
3256
|
sha_hex[:56],
|
3190
3257
|
sha_b64,
|
3191
3258
|
sz,
|
@@ -3201,13 +3268,14 @@ class HttpCli(object):
|
|
3201
3268
|
self.host,
|
3202
3269
|
rel_url,
|
3203
3270
|
),
|
3204
|
-
"sha512": sha_hex[:56],
|
3205
|
-
"sha_b64": sha_b64,
|
3206
3271
|
"sz": sz,
|
3207
3272
|
"fn": lfn,
|
3208
3273
|
"fn_orig": ofn,
|
3209
3274
|
"path": rel_url,
|
3210
3275
|
}
|
3276
|
+
if halg:
|
3277
|
+
jpart[halg] = sha_hex[:56]
|
3278
|
+
jpart["sha_b64"] = sha_b64
|
3211
3279
|
jmsg["files"].append(jpart)
|
3212
3280
|
|
3213
3281
|
vspd = self._spd(sz_total, False)
|
@@ -4600,6 +4668,18 @@ class HttpCli(object):
|
|
4600
4668
|
if "th" in self.ouparam:
|
4601
4669
|
return self.tx_svg("e" + pt[:3])
|
4602
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
|
+
|
4603
4683
|
t = t.format(self.args.SR)
|
4604
4684
|
qv = quotep(self.vpaths) + self.ourlq()
|
4605
4685
|
html = self.j2s(
|
@@ -5240,7 +5320,7 @@ class HttpCli(object):
|
|
5240
5320
|
st = bos.stat(abspath)
|
5241
5321
|
except:
|
5242
5322
|
if "on404" not in vn.flags:
|
5243
|
-
return self.tx_404()
|
5323
|
+
return self.tx_404(not self.can_read)
|
5244
5324
|
|
5245
5325
|
ret = self.on40x(vn.flags["on404"], vn, rem)
|
5246
5326
|
if ret == "true":
|
@@ -5251,9 +5331,9 @@ class HttpCli(object):
|
|
5251
5331
|
try:
|
5252
5332
|
st = bos.stat(abspath)
|
5253
5333
|
except:
|
5254
|
-
return self.tx_404()
|
5334
|
+
return self.tx_404(not self.can_read)
|
5255
5335
|
else:
|
5256
|
-
return self.tx_404()
|
5336
|
+
return self.tx_404(not self.can_read)
|
5257
5337
|
|
5258
5338
|
if rem.startswith(".hist/up2k.") or (
|
5259
5339
|
rem.endswith("/dir.txt") and rem.startswith(".hist/th/")
|
@@ -5380,13 +5460,13 @@ class HttpCli(object):
|
|
5380
5460
|
vrem = vjoin(vrem, fn)
|
5381
5461
|
abspath = ap2
|
5382
5462
|
break
|
5383
|
-
elif self.vpath.rsplit("/", 1)[1] in ("index.htm", "index.html"):
|
5463
|
+
elif self.vpath.rsplit("/", 1)[-1] in ("index.htm", "index.html"):
|
5384
5464
|
fk_pass = True
|
5385
5465
|
|
5386
5466
|
if not is_dir and (self.can_read or self.can_get):
|
5387
5467
|
if not self.can_read and not fk_pass and "fk" in vn.flags:
|
5388
5468
|
if not use_filekey:
|
5389
|
-
return self.tx_404()
|
5469
|
+
return self.tx_404(True)
|
5390
5470
|
|
5391
5471
|
if add_og and not abspath.lower().endswith(".md"):
|
5392
5472
|
if og_ua or self.host not in self.headers.get("referer", ""):
|
@@ -5474,61 +5554,28 @@ class HttpCli(object):
|
|
5474
5554
|
is_js = False
|
5475
5555
|
|
5476
5556
|
vf = vn.flags
|
5477
|
-
unlist = vf.get("unlist", "")
|
5478
5557
|
ls_ret = {
|
5479
5558
|
"dirs": [],
|
5480
5559
|
"files": [],
|
5481
5560
|
"taglist": [],
|
5482
5561
|
"srvinf": srv_infot,
|
5483
5562
|
"acct": self.uname,
|
5484
|
-
"idx": e2d,
|
5485
|
-
"itag": e2t,
|
5486
|
-
"dsort": vf["sort"],
|
5487
|
-
"dcrop": vf["crop"],
|
5488
|
-
"dth3x": vf["th3x"],
|
5489
|
-
"u2ts": vf["u2ts"],
|
5490
|
-
"lifetime": vn.flags.get("lifetime") or 0,
|
5491
|
-
"frand": bool(vn.flags.get("rand")),
|
5492
|
-
"unlist": unlist,
|
5493
5563
|
"perms": perms,
|
5564
|
+
"cfg": vn.js_ls,
|
5494
5565
|
}
|
5495
5566
|
cgv = {
|
5496
5567
|
"ls0": None,
|
5497
5568
|
"acct": self.uname,
|
5498
5569
|
"perms": perms,
|
5499
|
-
"u2ts": vf["u2ts"],
|
5500
|
-
"lifetime": ls_ret["lifetime"],
|
5501
|
-
"frand": bool(vn.flags.get("rand")),
|
5502
|
-
"def_hcols": [],
|
5503
|
-
"have_emp": self.args.emp,
|
5504
|
-
"have_up2k_idx": e2d,
|
5505
|
-
"have_acode": (not self.args.no_acode),
|
5506
|
-
"have_mv": (not self.args.no_mv),
|
5507
|
-
"have_del": (not self.args.no_del),
|
5508
|
-
"have_zip": (not self.args.no_zip),
|
5509
|
-
"have_shr": self.args.shr,
|
5510
|
-
"have_unpost": int(self.args.unpost),
|
5511
|
-
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
5512
|
-
"dgrid": "grid" in vf,
|
5513
|
-
"dgsel": "gsel" in vf,
|
5514
|
-
"dsort": vf["sort"],
|
5515
|
-
"dcrop": vf["crop"],
|
5516
|
-
"dth3x": vf["th3x"],
|
5517
|
-
"dvol": self.args.au_vol,
|
5518
|
-
"themes": self.args.themes,
|
5519
|
-
"turbolvl": self.args.turbo,
|
5520
|
-
"u2j": self.args.u2j,
|
5521
|
-
"u2sz": self.args.u2sz,
|
5522
|
-
"idxh": int(self.args.ih),
|
5523
|
-
"u2sort": self.args.u2sort,
|
5524
5570
|
}
|
5525
5571
|
j2a = {
|
5572
|
+
"cgv1": vn.js_htm,
|
5526
5573
|
"cgv": cgv,
|
5527
5574
|
"vpnodes": vpnodes,
|
5528
5575
|
"files": [],
|
5529
5576
|
"ls0": None,
|
5530
5577
|
"taglist": [],
|
5531
|
-
"have_tags_idx": e2t,
|
5578
|
+
"have_tags_idx": int(e2t),
|
5532
5579
|
"have_b_u": (self.can_write and self.uparam.get("b") == "u"),
|
5533
5580
|
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
|
5534
5581
|
"url_suf": url_suf,
|
@@ -5899,17 +5946,12 @@ class HttpCli(object):
|
|
5899
5946
|
"dirs": dirs,
|
5900
5947
|
"files": files,
|
5901
5948
|
"taglist": taglist,
|
5902
|
-
"unlist": unlist,
|
5903
5949
|
}
|
5904
5950
|
j2a["files"] = []
|
5905
5951
|
else:
|
5906
5952
|
j2a["files"] = dirs + files
|
5907
5953
|
|
5908
5954
|
j2a["taglist"] = taglist
|
5909
|
-
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
5910
|
-
|
5911
|
-
if "mth" in vn.flags:
|
5912
|
-
j2a["def_hcols"] = list(vn.flags["mth"])
|
5913
5955
|
|
5914
5956
|
if add_og and "raw" not in self.uparam:
|
5915
5957
|
j2a["this"] = self
|
copyparty/httpsrv.py
CHANGED
@@ -132,7 +132,7 @@ class HttpSrv(object):
|
|
132
132
|
dls = {} # state
|
133
133
|
self.dli = self.tdli = dli
|
134
134
|
self.dls = self.tdls = dls
|
135
|
-
self.iiam = '<img src="%s.cpr/iiam.gif" />' % (self.args.SRS,)
|
135
|
+
self.iiam = '<img src="%s.cpr/iiam.gif?cache=i" />' % (self.args.SRS,)
|
136
136
|
|
137
137
|
self.bound = set()
|
138
138
|
self.name = "hsrv" + nsuf
|
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
|
)
|