copyparty 1.13.3__py3-none-any.whl → 1.13.5__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 +80 -41
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +68 -9
- copyparty/broker_util.py +3 -3
- copyparty/cert.py +10 -6
- copyparty/cfg.py +3 -0
- copyparty/ftpd.py +44 -7
- copyparty/httpcli.py +224 -96
- copyparty/httpsrv.py +3 -3
- copyparty/mdns.py +1 -1
- copyparty/mtag.py +3 -0
- copyparty/smbd.py +1 -1
- copyparty/ssdp.py +1 -1
- copyparty/svchub.py +4 -2
- copyparty/tcpsrv.py +4 -1
- copyparty/tftpd.py +5 -10
- copyparty/th_cli.py +3 -2
- copyparty/th_srv.py +16 -8
- copyparty/up2k.py +124 -40
- copyparty/util.py +45 -15
- copyparty/web/a/u2c.py +117 -38
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/svcs.html +11 -10
- copyparty/web/ui.css.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/METADATA +45 -10
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/RECORD +35 -35
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/WHEEL +1 -1
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/LICENSE +0 -0
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.3.dist-info → copyparty-1.13.5.dist-info}/top_level.txt +0 -0
copyparty/ssdp.py
CHANGED
copyparty/svchub.py
CHANGED
@@ -473,8 +473,10 @@ class SvcHub(object):
|
|
473
473
|
zsl = al.th_covers.split(",")
|
474
474
|
zsl = [x.strip() for x in zsl]
|
475
475
|
zsl = [x for x in zsl if x]
|
476
|
-
al.th_covers =
|
477
|
-
al.th_coversd =
|
476
|
+
al.th_covers = zsl
|
477
|
+
al.th_coversd = zsl + ["." + x for x in zsl]
|
478
|
+
al.th_covers_set = set(al.th_covers)
|
479
|
+
al.th_coversd_set = set(al.th_coversd)
|
478
480
|
|
479
481
|
for k in "c".split(" "):
|
480
482
|
vl = getattr(al, k)
|
copyparty/tcpsrv.py
CHANGED
@@ -15,6 +15,7 @@ from .util import (
|
|
15
15
|
E_ADDR_IN_USE,
|
16
16
|
E_ADDR_NOT_AVAIL,
|
17
17
|
E_UNREACH,
|
18
|
+
HAVE_IPV6,
|
18
19
|
IP6ALL,
|
19
20
|
Netdev,
|
20
21
|
min_ex,
|
@@ -108,8 +109,10 @@ class TcpSrv(object):
|
|
108
109
|
|
109
110
|
eps = {
|
110
111
|
"127.0.0.1": Netdev("127.0.0.1", 0, "", "local only"),
|
111
|
-
"::1": Netdev("::1", 0, "", "local only"),
|
112
112
|
}
|
113
|
+
if HAVE_IPV6:
|
114
|
+
eps["::1"] = Netdev("::1", 0, "", "local only")
|
115
|
+
|
113
116
|
nonlocals = [x for x in self.args.i if x not in [k.split("/")[0] for k in eps]]
|
114
117
|
if nonlocals:
|
115
118
|
try:
|
copyparty/tftpd.py
CHANGED
@@ -33,7 +33,7 @@ from partftpy import (
|
|
33
33
|
)
|
34
34
|
from partftpy.TftpShared import TftpException
|
35
35
|
|
36
|
-
from .__init__ import EXE, TYPE_CHECKING
|
36
|
+
from .__init__ import EXE, PY2, TYPE_CHECKING
|
37
37
|
from .authsrv import VFS
|
38
38
|
from .bos import bos
|
39
39
|
from .util import BytesIO, Daemon, ODict, exclude_dotfiles, min_ex, runhook, undot
|
@@ -92,7 +92,7 @@ class Tftpd(object):
|
|
92
92
|
TftpServer,
|
93
93
|
]
|
94
94
|
cbak = []
|
95
|
-
if not self.args.tftp_no_fast and not EXE:
|
95
|
+
if not self.args.tftp_no_fast and not EXE and not PY2:
|
96
96
|
try:
|
97
97
|
ptn = re.compile(r"(^\s*)log\.debug\(.*\)$")
|
98
98
|
for C in Cs:
|
@@ -102,7 +102,7 @@ class Tftpd(object):
|
|
102
102
|
cfn = C.__spec__.origin
|
103
103
|
exec (compile(src2, filename=cfn, mode="exec"), C.__dict__)
|
104
104
|
except Exception:
|
105
|
-
t = "failed to optimize tftp code; run with --tftp-
|
105
|
+
t = "failed to optimize tftp code; run with --tftp-no-fast if there are issues:\n"
|
106
106
|
self.log("tftp", t + min_ex(), 3)
|
107
107
|
for n, zd in enumerate(cbak):
|
108
108
|
Cs[n].__dict__ = zd
|
@@ -147,11 +147,6 @@ class Tftpd(object):
|
|
147
147
|
|
148
148
|
self._disarm(fos)
|
149
149
|
|
150
|
-
ip = next((x for x in self.args.i if ":" not in x), None)
|
151
|
-
if not ip:
|
152
|
-
self.log("tftp", "IPv6 not supported for tftp; listening on 0.0.0.0", 3)
|
153
|
-
ip = "0.0.0.0"
|
154
|
-
|
155
150
|
self.port = int(self.args.tftp)
|
156
151
|
self.srv = []
|
157
152
|
self.ips = []
|
@@ -165,7 +160,7 @@ class Tftpd(object):
|
|
165
160
|
if "::" in ips:
|
166
161
|
ips.append("0.0.0.0")
|
167
162
|
|
168
|
-
if self.args.
|
163
|
+
if self.args.tftp4:
|
169
164
|
ips = [x for x in ips if ":" not in x]
|
170
165
|
|
171
166
|
ips = list(ODict.fromkeys(ips)) # dedup
|
@@ -330,7 +325,7 @@ class Tftpd(object):
|
|
330
325
|
|
331
326
|
xbu = vfs.flags.get("xbu")
|
332
327
|
if xbu and not runhook(
|
333
|
-
self.nlog, xbu, ap, vpath, "", "", 0, 0, "8.3.8.7", 0, ""
|
328
|
+
self.nlog, xbu, ap, vpath, "", "", "", 0, 0, "8.3.8.7", 0, ""
|
334
329
|
):
|
335
330
|
yeet("blocked by xbu server config: " + vpath)
|
336
331
|
|
copyparty/th_cli.py
CHANGED
@@ -56,7 +56,8 @@ class ThumbCli(object):
|
|
56
56
|
|
57
57
|
want_opus = fmt in ("opus", "caf", "mp3")
|
58
58
|
is_au = ext in self.fmt_ffa
|
59
|
-
|
59
|
+
is_vau = want_opus and ext in self.fmt_ffv
|
60
|
+
if is_au or is_vau:
|
60
61
|
if want_opus:
|
61
62
|
if self.args.no_acode:
|
62
63
|
return None
|
@@ -104,7 +105,7 @@ class ThumbCli(object):
|
|
104
105
|
|
105
106
|
fmt = sfmt
|
106
107
|
|
107
|
-
elif fmt[:1] == "p" and not is_au:
|
108
|
+
elif fmt[:1] == "p" and not is_au and not is_vid:
|
108
109
|
t = "cannot thumbnail [%s]: png only allowed for waveforms"
|
109
110
|
self.log(t % (rem), 6)
|
110
111
|
return None
|
copyparty/th_srv.py
CHANGED
@@ -301,23 +301,31 @@ class ThumbSrv(object):
|
|
301
301
|
ap_unpk = abspath
|
302
302
|
|
303
303
|
if not bos.path.exists(tpath):
|
304
|
+
want_mp3 = tpath.endswith(".mp3")
|
305
|
+
want_opus = tpath.endswith(".opus") or tpath.endswith(".caf")
|
306
|
+
want_png = tpath.endswith(".png")
|
307
|
+
want_au = want_mp3 or want_opus
|
304
308
|
for lib in self.args.th_dec:
|
309
|
+
can_au = lib == "ff" and (
|
310
|
+
ext in self.fmt_ffa or ext in self.fmt_ffv
|
311
|
+
)
|
312
|
+
|
305
313
|
if lib == "pil" and ext in self.fmt_pil:
|
306
314
|
funs.append(self.conv_pil)
|
307
315
|
elif lib == "vips" and ext in self.fmt_vips:
|
308
316
|
funs.append(self.conv_vips)
|
309
|
-
elif
|
310
|
-
|
311
|
-
elif lib == "ff" and ext in self.fmt_ffa:
|
312
|
-
if tpath.endswith(".opus") or tpath.endswith(".caf"):
|
317
|
+
elif can_au and (want_png or want_au):
|
318
|
+
if want_opus:
|
313
319
|
funs.append(self.conv_opus)
|
314
|
-
elif
|
320
|
+
elif want_mp3:
|
315
321
|
funs.append(self.conv_mp3)
|
316
|
-
elif
|
322
|
+
elif want_png:
|
317
323
|
funs.append(self.conv_waves)
|
318
324
|
png_ok = True
|
319
|
-
|
320
|
-
|
325
|
+
elif lib == "ff" and (ext in self.fmt_ffi or ext in self.fmt_ffv):
|
326
|
+
funs.append(self.conv_ffmpeg)
|
327
|
+
elif lib == "ff" and ext in self.fmt_ffa and not want_au:
|
328
|
+
funs.append(self.conv_spec)
|
321
329
|
|
322
330
|
tdir, tfn = os.path.split(tpath)
|
323
331
|
ttpath = os.path.join(tdir, "w", tfn)
|
copyparty/up2k.py
CHANGED
@@ -651,7 +651,7 @@ class Up2k(object):
|
|
651
651
|
return False, flags
|
652
652
|
|
653
653
|
ret = {k: v for k, v in flags.items() if not k.startswith("e2t")}
|
654
|
-
if ret
|
654
|
+
if len(ret) == len(flags):
|
655
655
|
return False, flags
|
656
656
|
|
657
657
|
return True, ret
|
@@ -1192,6 +1192,9 @@ class Up2k(object):
|
|
1192
1192
|
fat32 = True
|
1193
1193
|
cv = ""
|
1194
1194
|
|
1195
|
+
th_cvd = self.args.th_coversd
|
1196
|
+
th_cvds = self.args.th_coversd_set
|
1197
|
+
|
1195
1198
|
assert self.pp and self.mem_cur
|
1196
1199
|
self.pp.msg = "a%d %s" % (self.pp.n, cdir)
|
1197
1200
|
|
@@ -1276,12 +1279,21 @@ class Up2k(object):
|
|
1276
1279
|
|
1277
1280
|
files.append((sz, lmod, iname))
|
1278
1281
|
liname = iname.lower()
|
1279
|
-
if
|
1280
|
-
|
1281
|
-
|
1282
|
+
if (
|
1283
|
+
sz
|
1284
|
+
and (
|
1285
|
+
liname in th_cvds
|
1286
|
+
or (
|
1287
|
+
not cv
|
1288
|
+
and liname.rsplit(".", 1)[-1] in CV_EXTS
|
1289
|
+
and not iname.startswith(".")
|
1290
|
+
)
|
1291
|
+
)
|
1292
|
+
and (
|
1282
1293
|
not cv
|
1283
|
-
|
1284
|
-
|
1294
|
+
or liname not in th_cvds
|
1295
|
+
or cv.lower() not in th_cvds
|
1296
|
+
or th_cvd.index(liname) < th_cvd.index(cv.lower())
|
1285
1297
|
)
|
1286
1298
|
):
|
1287
1299
|
cv = iname
|
@@ -2755,6 +2767,7 @@ class Up2k(object):
|
|
2755
2767
|
job["vtop"],
|
2756
2768
|
job["host"],
|
2757
2769
|
job["user"],
|
2770
|
+
self.asrv.vfs.get_perms(job["vtop"], job["user"]),
|
2758
2771
|
job["lmod"],
|
2759
2772
|
job["size"],
|
2760
2773
|
job["addr"],
|
@@ -2997,8 +3010,8 @@ class Up2k(object):
|
|
2997
3010
|
times = (int(time.time()), int(lmod))
|
2998
3011
|
bos.utime(dst, times, False)
|
2999
3012
|
|
3000
|
-
def
|
3001
|
-
self, ptop , wark ,
|
3013
|
+
def handle_chunks(
|
3014
|
+
self, ptop , wark , chashes
|
3002
3015
|
) :
|
3003
3016
|
with self.mutex, self.reg_mutex:
|
3004
3017
|
self.db_act = self.vol_act[ptop] = time.time()
|
@@ -3008,26 +3021,37 @@ class Up2k(object):
|
|
3008
3021
|
self.log("unknown wark [{}], known: {}".format(wark, known))
|
3009
3022
|
raise Pebkac(400, "unknown wark" + SSEELOG)
|
3010
3023
|
|
3011
|
-
|
3012
|
-
|
3013
|
-
|
3014
|
-
|
3015
|
-
|
3024
|
+
for chash in chashes:
|
3025
|
+
if chash not in job["need"]:
|
3026
|
+
msg = "chash = {} , need:\n".format(chash)
|
3027
|
+
msg += "\n".join(job["need"])
|
3028
|
+
self.log(msg)
|
3029
|
+
raise Pebkac(400, "already got that (%s) but thanks??" % (chash,))
|
3030
|
+
|
3031
|
+
if chash in job["busy"]:
|
3032
|
+
nh = len(job["hash"])
|
3033
|
+
idx = job["hash"].index(chash)
|
3034
|
+
t = "that chunk is already being written to:\n {}\n {} {}/{}\n {}"
|
3035
|
+
raise Pebkac(400, t.format(wark, chash, idx, nh, job["name"]))
|
3016
3036
|
|
3017
|
-
|
3018
|
-
if not nchunk:
|
3019
|
-
raise Pebkac(400, "unknown chunk")
|
3037
|
+
chunksize = up2k_chunksize(job["size"])
|
3020
3038
|
|
3021
|
-
|
3022
|
-
|
3023
|
-
|
3024
|
-
|
3025
|
-
|
3039
|
+
coffsets = []
|
3040
|
+
for chash in chashes:
|
3041
|
+
nchunk = [n for n, v in enumerate(job["hash"]) if v == chash]
|
3042
|
+
if not nchunk:
|
3043
|
+
raise Pebkac(400, "unknown chunk %s" % (chash))
|
3026
3044
|
|
3027
|
-
|
3045
|
+
ofs = [chunksize * x for x in nchunk]
|
3046
|
+
coffsets.append(ofs)
|
3028
3047
|
|
3029
|
-
|
3030
|
-
|
3048
|
+
for ofs1, ofs2 in zip(coffsets, coffsets[1:]):
|
3049
|
+
gap = (ofs2[0] - ofs1[0]) - chunksize
|
3050
|
+
if gap:
|
3051
|
+
t = "only sibling chunks can be stitched; gap of %d bytes between offsets %d and %d in %s"
|
3052
|
+
raise Pebkac(400, t % (gap, ofs1[0], ofs2[0], job["name"]))
|
3053
|
+
|
3054
|
+
path = djoin(job["ptop"], job["prel"], job["tnam"])
|
3031
3055
|
|
3032
3056
|
if not job["sprs"]:
|
3033
3057
|
cur_sz = bos.path.getsize(path)
|
@@ -3040,17 +3064,20 @@ class Up2k(object):
|
|
3040
3064
|
|
3041
3065
|
job["poke"] = time.time()
|
3042
3066
|
|
3043
|
-
return chunksize,
|
3067
|
+
return chunksize, coffsets, path, job["lmod"], job["sprs"]
|
3044
3068
|
|
3045
|
-
def
|
3069
|
+
def release_chunks(self, ptop , wark , chashes ) :
|
3046
3070
|
with self.reg_mutex:
|
3047
3071
|
job = self.registry[ptop].get(wark)
|
3048
3072
|
if job:
|
3049
|
-
|
3073
|
+
for chash in chashes:
|
3074
|
+
job["busy"].pop(chash, None)
|
3050
3075
|
|
3051
3076
|
return True
|
3052
3077
|
|
3053
|
-
def
|
3078
|
+
def confirm_chunks(
|
3079
|
+
self, ptop , wark , chashes
|
3080
|
+
) :
|
3054
3081
|
with self.mutex, self.reg_mutex:
|
3055
3082
|
self.db_act = self.vol_act[ptop] = time.time()
|
3056
3083
|
try:
|
@@ -3059,14 +3086,16 @@ class Up2k(object):
|
|
3059
3086
|
src = djoin(pdir, job["tnam"])
|
3060
3087
|
dst = djoin(pdir, job["name"])
|
3061
3088
|
except Exception as ex:
|
3062
|
-
return "confirm_chunk, wark
|
3089
|
+
return "confirm_chunk, wark(%r)" % (ex,) # type: ignore
|
3063
3090
|
|
3064
|
-
|
3091
|
+
for chash in chashes:
|
3092
|
+
job["busy"].pop(chash, None)
|
3065
3093
|
|
3066
3094
|
try:
|
3067
|
-
|
3095
|
+
for chash in chashes:
|
3096
|
+
job["need"].remove(chash)
|
3068
3097
|
except Exception as ex:
|
3069
|
-
return "confirm_chunk, chash
|
3098
|
+
return "confirm_chunk, chash(%s) %r" % (chash, ex) # type: ignore
|
3070
3099
|
|
3071
3100
|
ret = len(job["need"])
|
3072
3101
|
if ret > 0:
|
@@ -3077,7 +3106,7 @@ class Up2k(object):
|
|
3077
3106
|
|
3078
3107
|
return ret, dst
|
3079
3108
|
|
3080
|
-
def finish_upload(self, ptop , wark , busy_aps
|
3109
|
+
def finish_upload(self, ptop , wark , busy_aps ) :
|
3081
3110
|
self.busy_aps = busy_aps
|
3082
3111
|
with self.mutex, self.reg_mutex:
|
3083
3112
|
self._finish_upload(ptop, wark)
|
@@ -3282,6 +3311,7 @@ class Up2k(object):
|
|
3282
3311
|
djoin(vtop, rd, fn),
|
3283
3312
|
host,
|
3284
3313
|
usr,
|
3314
|
+
self.asrv.vfs.get_perms(djoin(vtop, rd, fn), usr),
|
3285
3315
|
int(ts),
|
3286
3316
|
sz,
|
3287
3317
|
ip,
|
@@ -3316,15 +3346,29 @@ class Up2k(object):
|
|
3316
3346
|
with self.rescan_cond:
|
3317
3347
|
self.rescan_cond.notify_all()
|
3318
3348
|
|
3319
|
-
if rd and sz and fn.lower() in self.args.
|
3349
|
+
if rd and sz and fn.lower() in self.args.th_coversd_set:
|
3320
3350
|
# wasteful; db_add will re-index actual covers
|
3321
3351
|
# but that won't catch existing files
|
3322
3352
|
crd, cdn = rd.rsplit("/", 1) if "/" in rd else ("", rd)
|
3323
3353
|
try:
|
3324
|
-
|
3325
|
-
db.execute(
|
3354
|
+
q = "select fn from cv where rd=? and dn=?"
|
3355
|
+
db_cv = db.execute(q, (crd, cdn)).fetchone()[0]
|
3356
|
+
db_lcv = db_cv.lower()
|
3357
|
+
if db_lcv in self.args.th_coversd_set:
|
3358
|
+
idx_db = self.args.th_coversd.index(db_lcv)
|
3359
|
+
idx_fn = self.args.th_coversd.index(fn.lower())
|
3360
|
+
add_cv = idx_fn < idx_db
|
3361
|
+
else:
|
3362
|
+
add_cv = True
|
3326
3363
|
except:
|
3327
|
-
|
3364
|
+
add_cv = True
|
3365
|
+
|
3366
|
+
if add_cv:
|
3367
|
+
try:
|
3368
|
+
db.execute("delete from cv where rd=? and dn=?", (crd, cdn))
|
3369
|
+
db.execute("insert into cv values (?,?,?)", (crd, cdn, fn))
|
3370
|
+
except:
|
3371
|
+
pass
|
3328
3372
|
|
3329
3373
|
def handle_rm(
|
3330
3374
|
self,
|
@@ -3467,6 +3511,7 @@ class Up2k(object):
|
|
3467
3511
|
vpath,
|
3468
3512
|
"",
|
3469
3513
|
uname,
|
3514
|
+
self.asrv.vfs.get_perms(vpath, uname),
|
3470
3515
|
stl.st_mtime,
|
3471
3516
|
st.st_size,
|
3472
3517
|
ip,
|
@@ -3500,6 +3545,7 @@ class Up2k(object):
|
|
3500
3545
|
vpath,
|
3501
3546
|
"",
|
3502
3547
|
uname,
|
3548
|
+
self.asrv.vfs.get_perms(vpath, uname),
|
3503
3549
|
stl.st_mtime,
|
3504
3550
|
st.st_size,
|
3505
3551
|
ip,
|
@@ -3632,7 +3678,18 @@ class Up2k(object):
|
|
3632
3678
|
xar = dvn.flags.get("xar")
|
3633
3679
|
if xbr:
|
3634
3680
|
if not runhook(
|
3635
|
-
self.log,
|
3681
|
+
self.log,
|
3682
|
+
xbr,
|
3683
|
+
sabs,
|
3684
|
+
svp,
|
3685
|
+
"",
|
3686
|
+
uname,
|
3687
|
+
self.asrv.vfs.get_perms(svp, uname),
|
3688
|
+
stl.st_mtime,
|
3689
|
+
st.st_size,
|
3690
|
+
"",
|
3691
|
+
0,
|
3692
|
+
"",
|
3636
3693
|
):
|
3637
3694
|
t = "move blocked by xbr server config: {}".format(svp)
|
3638
3695
|
self.log(t, 1)
|
@@ -3657,7 +3714,20 @@ class Up2k(object):
|
|
3657
3714
|
self.rescan_cond.notify_all()
|
3658
3715
|
|
3659
3716
|
if xar:
|
3660
|
-
runhook(
|
3717
|
+
runhook(
|
3718
|
+
self.log,
|
3719
|
+
xar,
|
3720
|
+
dabs,
|
3721
|
+
dvp,
|
3722
|
+
"",
|
3723
|
+
uname,
|
3724
|
+
self.asrv.vfs.get_perms(dvp, uname),
|
3725
|
+
0,
|
3726
|
+
0,
|
3727
|
+
"",
|
3728
|
+
0,
|
3729
|
+
"",
|
3730
|
+
)
|
3661
3731
|
|
3662
3732
|
return "k"
|
3663
3733
|
|
@@ -3756,7 +3826,20 @@ class Up2k(object):
|
|
3756
3826
|
wunlink(self.log, sabs, svn.flags)
|
3757
3827
|
|
3758
3828
|
if xar:
|
3759
|
-
runhook(
|
3829
|
+
runhook(
|
3830
|
+
self.log,
|
3831
|
+
xar,
|
3832
|
+
dabs,
|
3833
|
+
dvp,
|
3834
|
+
"",
|
3835
|
+
uname,
|
3836
|
+
self.asrv.vfs.get_perms(dvp, uname),
|
3837
|
+
0,
|
3838
|
+
0,
|
3839
|
+
"",
|
3840
|
+
0,
|
3841
|
+
"",
|
3842
|
+
)
|
3760
3843
|
|
3761
3844
|
return "k"
|
3762
3845
|
|
@@ -4045,6 +4128,7 @@ class Up2k(object):
|
|
4045
4128
|
vp_chk,
|
4046
4129
|
job["host"],
|
4047
4130
|
job["user"],
|
4131
|
+
self.asrv.vfs.get_perms(vp_chk, job["user"]),
|
4048
4132
|
int(job["lmod"]),
|
4049
4133
|
job["size"],
|
4050
4134
|
job["addr"],
|
copyparty/util.py
CHANGED
@@ -137,6 +137,18 @@ else:
|
|
137
137
|
from urllib import unquote # type: ignore # pylint: disable=no-name-in-module
|
138
138
|
|
139
139
|
|
140
|
+
try:
|
141
|
+
socket.inet_pton(socket.AF_INET6, "::1")
|
142
|
+
HAVE_IPV6 = True
|
143
|
+
except:
|
144
|
+
|
145
|
+
def inet_pton(fam, ip):
|
146
|
+
return socket.inet_aton(ip)
|
147
|
+
|
148
|
+
socket.inet_pton = inet_pton
|
149
|
+
HAVE_IPV6 = False
|
150
|
+
|
151
|
+
|
140
152
|
try:
|
141
153
|
struct.unpack(b">i", b"idgi")
|
142
154
|
spack = struct.pack # type: ignore
|
@@ -210,6 +222,7 @@ IMPLICATIONS = [
|
|
210
222
|
["e2vu", "e2v"],
|
211
223
|
["e2vp", "e2v"],
|
212
224
|
["e2v", "e2d"],
|
225
|
+
["tftpvv", "tftpv"],
|
213
226
|
["smbw", "smb"],
|
214
227
|
["smb1", "smb"],
|
215
228
|
["smbvvv", "smbvv"],
|
@@ -1343,7 +1356,7 @@ def vol_san(vols , txt ) :
|
|
1343
1356
|
def min_ex(max_lines = 8, reverse = False) :
|
1344
1357
|
et, ev, tb = sys.exc_info()
|
1345
1358
|
stb = traceback.extract_tb(tb) if tb else traceback.extract_stack()[:-1]
|
1346
|
-
fmt = "%s
|
1359
|
+
fmt = "%s:%d <%s>: %s"
|
1347
1360
|
ex = [fmt % (fp.split(os.sep)[-1], ln, fun, txt) for fp, ln, fun, txt in stb]
|
1348
1361
|
if et or ev or tb:
|
1349
1362
|
ex.append("[%s] %s" % (et.__name__ if et else "(anonymous)", ev))
|
@@ -2437,6 +2450,9 @@ def build_netmap(csv ):
|
|
2437
2450
|
csv += ", 127.0.0.0/8, ::1/128" # loopback
|
2438
2451
|
|
2439
2452
|
srcs = [x.strip() for x in csv.split(",") if x.strip()]
|
2453
|
+
if not HAVE_IPV6:
|
2454
|
+
srcs = [x for x in srcs if ":" not in x]
|
2455
|
+
|
2440
2456
|
cidrs = []
|
2441
2457
|
for zs in srcs:
|
2442
2458
|
if not zs.endswith("."):
|
@@ -2955,7 +2971,8 @@ def retchk(
|
|
2955
2971
|
|
2956
2972
|
def _parsehook(
|
2957
2973
|
log , cmd
|
2958
|
-
)
|
2974
|
+
) :
|
2975
|
+
areq = ""
|
2959
2976
|
chk = False
|
2960
2977
|
fork = False
|
2961
2978
|
jtxt = False
|
@@ -2980,8 +2997,12 @@ def _parsehook(
|
|
2980
2997
|
cap = int(arg[1:]) # 0=none 1=stdout 2=stderr 3=both
|
2981
2998
|
elif arg.startswith("k"):
|
2982
2999
|
kill = arg[1:] # [t]ree [m]ain [n]one
|
3000
|
+
elif arg.startswith("a"):
|
3001
|
+
areq = arg[1:] # required perms
|
2983
3002
|
elif arg.startswith("i"):
|
2984
3003
|
pass
|
3004
|
+
elif not arg:
|
3005
|
+
break
|
2985
3006
|
else:
|
2986
3007
|
t = "hook: invalid flag {} in {}"
|
2987
3008
|
(log or print)(t.format(arg, ocmd))
|
@@ -3008,9 +3029,11 @@ def _parsehook(
|
|
3008
3029
|
"capture": cap,
|
3009
3030
|
}
|
3010
3031
|
|
3011
|
-
|
3032
|
+
argv = cmd.split(",") if "," in cmd else [cmd]
|
3033
|
+
|
3034
|
+
argv[0] = os.path.expandvars(os.path.expanduser(argv[0]))
|
3012
3035
|
|
3013
|
-
return chk, fork, jtxt, wait, sp_ka,
|
3036
|
+
return areq, chk, fork, jtxt, wait, sp_ka, argv
|
3014
3037
|
|
3015
3038
|
|
3016
3039
|
def runihook(
|
@@ -3019,10 +3042,9 @@ def runihook(
|
|
3019
3042
|
vol ,
|
3020
3043
|
ups ,
|
3021
3044
|
) :
|
3022
|
-
|
3023
|
-
|
3024
|
-
|
3025
|
-
if cmd.endswith(".py"):
|
3045
|
+
_, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
|
3046
|
+
bcmd = [sfsenc(x) for x in acmd]
|
3047
|
+
if acmd[0].endswith(".py"):
|
3026
3048
|
bcmd = [sfsenc(pybin)] + bcmd
|
3027
3049
|
|
3028
3050
|
vps = [vjoin(*list(s3dec(x[3], x[4]))) for x in ups]
|
@@ -3047,7 +3069,7 @@ def runihook(
|
|
3047
3069
|
|
3048
3070
|
t0 = time.time()
|
3049
3071
|
if fork:
|
3050
|
-
Daemon(runcmd,
|
3072
|
+
Daemon(runcmd, cmd, bcmd, ka=sp_ka)
|
3051
3073
|
else:
|
3052
3074
|
rc, v, err = runcmd(bcmd, **sp_ka) # type: ignore
|
3053
3075
|
if chk and rc:
|
@@ -3068,14 +3090,20 @@ def _runhook(
|
|
3068
3090
|
vp ,
|
3069
3091
|
host ,
|
3070
3092
|
uname ,
|
3093
|
+
perms ,
|
3071
3094
|
mt ,
|
3072
3095
|
sz ,
|
3073
3096
|
ip ,
|
3074
3097
|
at ,
|
3075
3098
|
txt ,
|
3076
3099
|
) :
|
3077
|
-
|
3078
|
-
|
3100
|
+
areq, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
|
3101
|
+
if areq:
|
3102
|
+
for ch in areq:
|
3103
|
+
if ch not in perms:
|
3104
|
+
t = "user %s not allowed to run hook %s; need perms %s, have %s"
|
3105
|
+
log(t % (uname, cmd, areq, perms))
|
3106
|
+
return True # fallthrough to next hook
|
3079
3107
|
if jtxt:
|
3080
3108
|
ja = {
|
3081
3109
|
"ap": ap,
|
@@ -3086,21 +3114,22 @@ def _runhook(
|
|
3086
3114
|
"at": at or time.time(),
|
3087
3115
|
"host": host,
|
3088
3116
|
"user": uname,
|
3117
|
+
"perms": perms,
|
3089
3118
|
"txt": txt,
|
3090
3119
|
}
|
3091
3120
|
arg = json.dumps(ja)
|
3092
3121
|
else:
|
3093
3122
|
arg = txt or ap
|
3094
3123
|
|
3095
|
-
acmd
|
3096
|
-
if
|
3124
|
+
acmd += [arg]
|
3125
|
+
if acmd[0].endswith(".py"):
|
3097
3126
|
acmd = [pybin] + acmd
|
3098
3127
|
|
3099
3128
|
bcmd = [fsenc(x) if x == ap else sfsenc(x) for x in acmd]
|
3100
3129
|
|
3101
3130
|
t0 = time.time()
|
3102
3131
|
if fork:
|
3103
|
-
Daemon(runcmd,
|
3132
|
+
Daemon(runcmd, cmd, [bcmd], ka=sp_ka)
|
3104
3133
|
else:
|
3105
3134
|
rc, v, err = runcmd(bcmd, **sp_ka) # type: ignore
|
3106
3135
|
if chk and rc:
|
@@ -3121,6 +3150,7 @@ def runhook(
|
|
3121
3150
|
vp ,
|
3122
3151
|
host ,
|
3123
3152
|
uname ,
|
3153
|
+
perms ,
|
3124
3154
|
mt ,
|
3125
3155
|
sz ,
|
3126
3156
|
ip ,
|
@@ -3130,7 +3160,7 @@ def runhook(
|
|
3130
3160
|
vp = vp.replace("\\", "/")
|
3131
3161
|
for cmd in cmds:
|
3132
3162
|
try:
|
3133
|
-
if not _runhook(log, cmd, ap, vp, host, uname, mt, sz, ip, at, txt):
|
3163
|
+
if not _runhook(log, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt):
|
3134
3164
|
return False
|
3135
3165
|
except Exception as ex:
|
3136
3166
|
(log or print)("hook: {}".format(ex))
|