xbu/xau with custom message

This commit is contained in:
ed 2025-09-26 23:49:32 +00:00
parent 397ed5653b
commit df0fa9d1b7
6 changed files with 224 additions and 95 deletions

View file

@ -0,0 +1,61 @@
#!/usr/bin/env python3
import json
import os
import re
import sys
_ = r"""
reject file upload (with a nice explanation why)
example usage as global config:
--xbu j,c1,bin/hooks/reject-and-explain.py
example usage as a volflag (per-volume config):
-v srv/inc:inc:r:rw,ed:c,xbu=j,c1,bin/hooks/reject-and-explain.py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(share filesystem-path srv/inc as volume /inc,
readable by everyone, read-write for user 'ed',
running this plugin on all uploads with the params listed below)
example usage as a volflag in a copyparty config file:
[/inc]
srv/inc
accs:
r: *
rw: ed
flags:
xbu: j,c1,bin/hooks/reject-and-explain.py
parameters explained,
xbu = execute-before-upload (can also be xau, execute-after-upload)
j = this hook needs upload information as json (not just the filename)
c1 = this hook returns json on stdout, so tell copyparty to read that
"""
def main():
inf = json.loads(sys.argv[1])
vdir, fn = os.path.split(inf["vp"])
print("inf[vp] = %r" % (inf["vp"],), file=sys.stderr)
# reject upload if the following regex-pattern does not match:
ok = re.search(r"(^|/)day[0-9]+$", vdir, re.IGNORECASE)
if ok:
# allow the upload
print("{}")
return
# the upload was rejected; display the following errortext
# (NOTE: you can optionally mention {0!r} anywhere in the message (zero or more times), and it will be replaced with the file's URL)
errmsg = "Files can only be uploaded into a folder named 'DayN' where N is a number, for example 'Day573'. This file was REJECTED: "
errmsg += inf["vp"] # mention the file's url at the end of the message
print(json.dumps({"rejectmsg": errmsg}))
if __name__ == "__main__":
main()

View file

@ -493,24 +493,30 @@ class FtpHandler(FTPHandler):
return return
self.vfs_map[ap] = vp self.vfs_map[ap] = vp
xbu = vfs.flags.get("xbu") xbu = vfs.flags.get("xbu")
if xbu and not runhook( if xbu:
None, hr = runhook(
None, None,
self.hub.up2k, None,
"xbu.ftpd", self.hub.up2k,
xbu, "xbu.ftpd",
ap, xbu,
vp, ap,
"", vp,
self.uname, "",
self.hub.asrv.vfs.get_perms(vp, self.uname), self.uname,
0, self.hub.asrv.vfs.get_perms(vp, self.uname),
0, 0,
self.cli_ip, 0,
time.time(), self.cli_ip,
"", time.time(),
): "",
raise FSE("Upload blocked by xbu server config") )
t = hr.get("rejectmsg") or ""
if t or not hr:
if not t:
t = "Upload blocked by xbu server config: %r" % (vp,)
self.respond("550 %s" % (t,), logging.info)
return
# print("ftp_STOR: {} {} => {}".format(vp, mode, ap)) # print("ftp_STOR: {} {} => {}".format(vp, mode, ap))
ret = FTPHandler.ftp_STOR(self, file, mode) ret = FTPHandler.ftp_STOR(self, file, mode)

View file

@ -2268,8 +2268,10 @@ class HttpCli(object):
at, at,
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xbu server config" if t or not hr:
if not t:
t = "upload blocked by xbu server config: %r" % (vp,)
self.log(t, 1) self.log(t, 1)
raise Pebkac(403, t) raise Pebkac(403, t)
if hr.get("reloc"): if hr.get("reloc"):
@ -2401,8 +2403,10 @@ class HttpCli(object):
at, at,
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xau server config" if t or not hr:
if not t:
t = "upload blocked by xau server config: %r" % (vp,)
self.log(t, 1) self.log(t, 1)
wunlink(self.log, path, vfs.flags) wunlink(self.log, path, vfs.flags)
raise Pebkac(403, t) raise Pebkac(403, t)
@ -3214,11 +3218,38 @@ class HttpCli(object):
new_file += ".md" new_file += ".md"
sanitized = sanitize_fn(new_file, "") sanitized = sanitize_fn(new_file, "")
fdir = vfs.canonical(rem)
fn = os.path.join(fdir, sanitized)
for hn in ("xbu", "xau"):
xxu = vfs.flags.get(hn)
if xxu:
hr = runhook(
self.log,
self.conn.hsrv.broker,
None,
"%s.http.new-md" % (hn,),
xxu,
fn,
vjoin(self.vpath, sanitized),
self.host,
self.uname,
self.asrv.vfs.get_perms(self.vpath, self.uname),
time.time(),
0,
self.ip,
time.time(),
"",
)
t = hr.get("rejectmsg") or ""
if t or not hr:
if not t:
t = "new-md blocked by " + hn + " server config: %r"
t = t % (vjoin(vfs.vpath, rem),)
self.log(t, 1)
raise Pebkac(403, t)
if not nullwrite: if not nullwrite:
fdir = vfs.canonical(rem)
fn = os.path.join(fdir, sanitized)
if bos.path.exists(fn): if bos.path.exists(fn):
raise Pebkac(500, "that file exists already") raise Pebkac(500, "that file exists already")
@ -3382,8 +3413,11 @@ class HttpCli(object):
at, at,
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xbu server config" if t or not hr:
if not t:
t = "upload blocked by xbu server config: %r"
t = t % (vjoin(upload_vpath, fname),)
self.log(t, 1) self.log(t, 1)
raise Pebkac(403, t) raise Pebkac(403, t)
if hr.get("reloc"): if hr.get("reloc"):
@ -3486,8 +3520,11 @@ class HttpCli(object):
at, at,
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xau server config" if t or not hr:
if not t:
t = "upload blocked by xau server config: %r"
t = t % (vjoin(upload_vpath, fname),)
self.log(t, 1) self.log(t, 1)
wunlink(self.log, abspath, vfs.flags) wunlink(self.log, abspath, vfs.flags)
raise Pebkac(403, t) raise Pebkac(403, t)
@ -3779,7 +3816,7 @@ class HttpCli(object):
xbu = vfs.flags.get("xbu") xbu = vfs.flags.get("xbu")
if xbu: if xbu:
if not runhook( hr = runhook(
self.log, self.log,
self.conn.hsrv.broker, self.conn.hsrv.broker,
None, None,
@ -3795,8 +3832,11 @@ class HttpCli(object):
self.ip, self.ip,
time.time(), time.time(),
"", "",
): )
t = "save blocked by xbu server config" t = hr.get("rejectmsg") or ""
if t or not hr:
if not t:
t = "save blocked by xbu server config"
self.log(t, 1) self.log(t, 1)
raise Pebkac(403, t) raise Pebkac(403, t)
@ -3823,27 +3863,31 @@ class HttpCli(object):
sha512 = sha512[:56] sha512 = sha512[:56]
xau = vfs.flags.get("xau") xau = vfs.flags.get("xau")
if xau and not runhook( if xau:
self.log, hr = runhook(
self.conn.hsrv.broker, self.log,
None, self.conn.hsrv.broker,
"xau.http.txt", None,
xau, "xau.http.txt",
fp, xau,
self.vpath, fp,
self.host, self.vpath,
self.uname, self.host,
self.asrv.vfs.get_perms(self.vpath, self.uname), self.uname,
new_lastmod, self.asrv.vfs.get_perms(self.vpath, self.uname),
sz, new_lastmod,
self.ip, sz,
new_lastmod, self.ip,
"", new_lastmod,
): "",
t = "save blocked by xau server config" )
self.log(t, 1) t = hr.get("rejectmsg") or ""
wunlink(self.log, fp, vfs.flags) if t or not hr:
raise Pebkac(403, t) if not t:
t = "save blocked by xau server config"
self.log(t, 1)
wunlink(self.log, fp, vfs.flags)
raise Pebkac(403, t)
self.conn.hsrv.broker.say( self.conn.hsrv.broker.say(
"up2k.hash_file", "up2k.hash_file",

View file

@ -246,24 +246,29 @@ class SMB(object):
ap = absreal(ap) ap = absreal(ap)
xbu = vfs.flags.get("xbu") xbu = vfs.flags.get("xbu")
if xbu and not runhook( if xbu:
self.nlog, hr = runhook(
None, self.nlog,
self.hub.up2k, None,
"xbu.smb", self.hub.up2k,
xbu, "xbu.smb",
ap, xbu,
vpath, ap,
"", vpath,
"", "",
"", "",
0, "",
0, 0,
"1.7.6.2", 0,
time.time(), "1.7.6.2",
"", time.time(),
): "",
yeet("blocked by xbu server config: %r" % (vpath,)) )
t = hr.get("rejectmsg") or ""
if t or not hr:
if not t:
t = "blocked by xbu server config: %r" % (vpath,)
yeet(t)
ret = bos.open(ap, flags, *a, mode=chmod, **ka) ret = bos.open(ap, flags, *a, mode=chmod, **ka)
if wr: if wr:

View file

@ -363,24 +363,29 @@ class Tftpd(object):
yeet("blocked write; folder not world-deletable: /%s" % (vpath,)) yeet("blocked write; folder not world-deletable: /%s" % (vpath,))
xbu = vfs.flags.get("xbu") xbu = vfs.flags.get("xbu")
if xbu and not runhook( if xbu:
self.nlog, hr = runhook(
None, self.nlog,
self.hub.up2k, None,
"xbu.tftpd", self.hub.up2k,
xbu, "xbu.tftpd",
ap, xbu,
vpath, ap,
"", vpath,
"", "",
"", "",
0, "",
0, 0,
"8.3.8.7", 0,
time.time(), "8.3.8.7",
"", time.time(),
): "",
yeet("blocked by xbu server config: %r" % (vpath,)) )
t = hr.get("rejectmsg") or ""
if t or not hr:
if not t:
t = "upload blocked by xbu server config: %r" % (vpath,)
yeet(t)
if not self.args.tftp_nols and bos.path.isdir(ap): if not self.args.tftp_nols and bos.path.isdir(ap):
return self._ls(vpath, "", 0, True) return self._ls(vpath, "", 0, True)

View file

@ -3300,8 +3300,11 @@ class Up2k(object):
job["at"], job["at"],
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xbu server config: %r" % (dst,) if t or not hr:
if not t:
t = "upload blocked by xbu server config: %r"
t = t % (vp,)
self.log(t, 1) self.log(t, 1)
raise Pebkac(403, t) raise Pebkac(403, t)
if hr.get("reloc"): if hr.get("reloc"):
@ -3981,8 +3984,11 @@ class Up2k(object):
at or time.time(), at or time.time(),
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xau server config" if t or not hr:
if not t:
t = "upload blocked by xau server config: %r"
t = t % (djoin(vtop, rd, fn),)
self.log(t, 1) self.log(t, 1)
wunlink(self.log, dst, vflags) wunlink(self.log, dst, vflags)
self.registry[ptop].pop(wark, None) self.registry[ptop].pop(wark, None)
@ -5132,8 +5138,10 @@ class Up2k(object):
job["t0"], job["t0"],
"", "",
) )
if not hr: t = hr.get("rejectmsg") or ""
t = "upload blocked by xbu server config: %r" % (vp_chk,) if t or not hr:
if not t:
t = "upload blocked by xbu server config: %r" % (vp_chk,)
self.log(t, 1) self.log(t, 1)
raise Pebkac(403, t) raise Pebkac(403, t)
if hr.get("reloc"): if hr.get("reloc"):