rbac disk-info and --ver (closes #726);

options --du-who and --ver-who specifies who can see the disk-info
(disk-usage, disk-free) and server-version based on user permissions
This commit is contained in:
ed 2025-09-05 19:48:38 +00:00
parent 09f22993be
commit 19a4c45389
6 changed files with 73 additions and 10 deletions

View file

@ -1485,7 +1485,7 @@ def add_optouts(ap):
ap2.add_argument("--no-fs-abrt", action="store_true", help="disable ability to abort ongoing copy/move")
ap2.add_argument("-nth", action="store_true", help="no title hostname; don't show \033[33m--name\033[0m in <title>")
ap2.add_argument("-nih", action="store_true", help="no info hostname -- don't show in UI")
ap2.add_argument("-nid", action="store_true", help="no info disk-usage -- don't show in UI")
ap2.add_argument("-nid", action="store_true", help="no info disk-usage -- don't show in UI. This is the same as --du-who no")
ap2.add_argument("-nb", action="store_true", help="no powered-by-copyparty branding in UI")
ap2.add_argument("--zipmaxn", metavar="N", type=u, default="0", help="reject download-as-zip if more than \033[33mN\033[0m files in total; optionally takes a unit suffix: [\033[32m256\033[0m], [\033[32m9K\033[0m], [\033[32m4G\033[0m] (volflag=zipmaxn)")
ap2.add_argument("--zipmaxs", metavar="SZ", type=u, default="0", help="reject download-as-zip if total download size exceeds \033[33mSZ\033[0m bytes; optionally takes a unit suffix: [\033[32m256M\033[0m], [\033[32m4G\033[0m], [\033[32m2T\033[0m] (volflag=zipmaxs)")
@ -1763,7 +1763,11 @@ def add_ui(ap, retry):
ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
ap2.add_argument("--bname", metavar="TXT", type=u, default="--name", help="server name (displayed in filebrowser document title)")
ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-nb\033[0m")
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m). This is the same as --ver-who all")
ap2.add_argument("--ver-who", metavar="TXT", type=u, default="no", help="only show version for: [\033[32ma\033[0m]=admin-permission-anywhere, [\033[32mauth\033[0m]=authenticated, [\033[32mall\033[0m]=anyone")
ap2.add_argument("--du-who", metavar="TXT", type=u, default="all", help="only show disk usage for: [\033[32mno\033[0m]=nobody, [\033[32ma\033[0m]=admin-permission, [\033[32mrw\033[0m]=read-write, [\033[32mw\033[0m]=write, [\033[32mauth\033[0m]=authenticated, [\033[32mall\033[0m]=anyone (volflag=du_who)")
ap2.add_argument("--ver-iwho", type=int, default=0, help=argparse.SUPPRESS)
ap2.add_argument("--du-iwho", type=int, default=0, help=argparse.SUPPRESS)
ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
ap2.add_argument("--ctl-re", metavar="SEC", type=int, default=1, help="the controlpanel Refresh-button will autorefresh every SEC; [\033[32m0\033[0m] = just once")

View file

@ -1014,7 +1014,10 @@ class AuthSrv(object):
yield prev, True
def vf0(self):
return {"d2d": True, "tcolor": self.args.tcolor}
return {"d2d": True, "tcolor": self.args.tcolor, "du_iwho": self.args.du_iwho}
def vf0b(self):
return {"tcolor": self.args.tcolor, "du_iwho": self.args.du_iwho}
def idp_checkin(
self, broker: Optional["BrokerCli"], uname: str, gname: str
@ -1759,8 +1762,7 @@ class AuthSrv(object):
if hits:
t = "Hint: Found some config files in [%s], but these were not automatically loaded because they are in the wrong place%s %s\n"
self.log(t % (E.cfg, ehint, ", ".join(hits)), 3)
zvf = {"tcolor": self.args.tcolor}
vfs = VFS(self.log_func, absreal("."), "", "", axs, zvf)
vfs = VFS(self.log_func, absreal("."), "", "", axs, self.vf0b())
if not axs.uread:
self.badcfg1 = True
elif "" not in mount:
@ -2294,6 +2296,8 @@ class AuthSrv(object):
vol.lim.uid = vol.flags["uid"]
vol.lim.gid = vol.flags["gid"]
vol.flags["du_iwho"] = n_du_who(vol.flags["du_who"])
if vol.flags.get("og"):
self.args.uqe = True
@ -3474,6 +3478,30 @@ class AuthSrv(object):
self.log("generated config:\n\n" + "\n".join(ret))
def n_du_who(s: str) -> int:
if s == "all":
return 9
if s == "auth":
return 7
if s == "w":
return 5
if s == "rw":
return 4
if s == "a":
return 3
return 0
def n_ver_who(s: str) -> int:
if s == "all":
return 9
if s == "auth":
return 6
if s == "a":
return 3
return 0
def split_cfg_ln(ln: str) -> dict[str, Any]:
# "a, b, c: 3" => {a:true, b:true, c:3}
ret = {}

View file

@ -84,6 +84,7 @@ def vf_vmap() -> dict[str, str]:
"chmod_d",
"chmod_f",
"dbd",
"du_who",
"forget_ip",
"hsortn",
"html_head",
@ -296,6 +297,7 @@ flagcats = {
"html_head=TXT": "includes TXT in the <head>, or @PATH for file at PATH",
"tcolor=#fc0": "theme color (a hint for webbrowsers, discord, etc.)",
"nodirsz": "don't show total folder size",
"du_who=all": "show disk-usage info to everyone",
"robots": "allows indexing by search engines (default)",
"norobots": "kindly asks search engines to leave",
"unlistcr": "don't list read-access in controlpanel",

View file

@ -1632,7 +1632,14 @@ class HttpCli(object):
self.log("inaccessible: %r" % ("/" + self.vpath,))
raise Pebkac(401, "authenticate")
if "quota-available-bytes" in props and not self.args.nid:
zi = vn.flags["du_iwho"] if "quota-available-bytes" in props else 0
if zi and (
zi == 9
or (zi == 7 and self.uname != "*")
or (zi == 5 and self.can_write)
or (zi == 4 and self.can_write and self.can_read)
or (zi == 3 and self.can_admin)
):
bfree, btot, _ = get_df(vn.realpath, False)
if btot:
df = {
@ -5159,6 +5166,11 @@ class HttpCli(object):
elif nre:
re_btn = "&re=%s" % (nre,)
zi = self.args.ver_iwho
show_ver = zi and (
zi == 9 or (zi == 6 and self.uname != "*") or (zi == 3 and avol)
)
html = self.j2s(
"splash",
this=self,
@ -5181,7 +5193,7 @@ class HttpCli(object):
no304=self.no304(),
k304vis=self.args.k304 > 0,
no304vis=self.args.no304 > 0,
ver=S_VERSION if self.args.ver else "",
ver=S_VERSION if show_ver else "",
chpw=self.args.chpw and self.uname != "*",
ahttps="" if self.is_https else "https://" + self.host + self.req,
)
@ -6360,7 +6372,14 @@ class HttpCli(object):
except:
self.log("#wow #whoa")
if not self.args.nid:
zi = vn.flags["du_iwho"]
if zi and (
zi == 9
or (zi == 7 and self.uname != "*")
or (zi == 5 and self.can_write)
or (zi == 4 and self.can_write and self.can_read)
or (zi == 3 and self.can_admin)
):
free, total, zs = get_df(abspath, False)
if total:
h1 = humansize(free or 0)

View file

@ -27,7 +27,7 @@ if True: # pylint: disable=using-constant-test
from typing import Any, Optional, Union
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
from .authsrv import BAD_CFG, AuthSrv
from .authsrv import BAD_CFG, AuthSrv, n_du_who, n_ver_who
from .bos import bos
from .cert import ensure_cert
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
@ -289,6 +289,14 @@ class SvcHub(object):
ch = "abcdefghijklmnopqrstuvwx"[int(args.theme / 2)]
args.theme = "{0}{1} {0} {1}".format(ch, bri)
if args.nid:
args.du_who = "no"
args.du_iwho = n_du_who(args.du_who)
if args.ver and args.ver_who == "no":
args.ver_who = "all"
args.ver_iwho = n_ver_who(args.ver_who)
if args.nih:
args.vname = ""
args.doctitle = args.doctitle.replace(" @ --name", "")

View file

@ -158,7 +158,7 @@ class Cfg(Namespace):
ex = "hash_mt hsortn qdel safe_dedup srch_time tail_fd tail_rate th_spec_p u2abort u2j u2sz unp_who"
ka.update(**{k: 1 for k in ex.split()})
ex = "ac_convt au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who"
ex = "ac_convt au_vol dl_list du_iwho mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who ver_iwho zip_who"
ka.update(**{k: 9 for k in ex.split()})
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
@ -189,6 +189,7 @@ class Cfg(Namespace):
cookie_cmax=8192,
cookie_nmax=50,
dbd="wal",
du_who="all",
dk_salt="b" * 16,
fk_salt="a" * 16,
grp_all="acct",
@ -220,6 +221,7 @@ class Cfg(Namespace):
u2sort="s",
u2ts="c",
unpost=600,
ver_who="all",
warksalt="hunter2",
**ka
)