mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
new permission G returns filekey on write-only uploads
This commit is contained in:
parent
b8a93e74bf
commit
d8bddede6a
|
@ -879,7 +879,7 @@ def main(argv: Optional[list[str]] = None) -> None:
|
||||||
if re.match("c[^,]", opt):
|
if re.match("c[^,]", opt):
|
||||||
mod = True
|
mod = True
|
||||||
na.append("c," + opt[1:])
|
na.append("c," + opt[1:])
|
||||||
elif re.sub("^[rwmdg]*", "", opt) and "," not in opt:
|
elif re.sub("^[rwmdgG]*", "", opt) and "," not in opt:
|
||||||
mod = True
|
mod = True
|
||||||
perm = opt[0]
|
perm = opt[0]
|
||||||
if perm == "a":
|
if perm == "a":
|
||||||
|
|
|
@ -58,18 +58,20 @@ class AXS(object):
|
||||||
umove: Optional[Union[list[str], set[str]]] = None,
|
umove: Optional[Union[list[str], set[str]]] = None,
|
||||||
udel: Optional[Union[list[str], set[str]]] = None,
|
udel: Optional[Union[list[str], set[str]]] = None,
|
||||||
uget: Optional[Union[list[str], set[str]]] = None,
|
uget: Optional[Union[list[str], set[str]]] = None,
|
||||||
|
upget: Optional[Union[list[str], set[str]]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.uread: set[str] = set(uread or [])
|
self.uread: set[str] = set(uread or [])
|
||||||
self.uwrite: set[str] = set(uwrite or [])
|
self.uwrite: set[str] = set(uwrite or [])
|
||||||
self.umove: set[str] = set(umove or [])
|
self.umove: set[str] = set(umove or [])
|
||||||
self.udel: set[str] = set(udel or [])
|
self.udel: set[str] = set(udel or [])
|
||||||
self.uget: set[str] = set(uget or [])
|
self.uget: set[str] = set(uget or [])
|
||||||
|
self.upget: set[str] = set(upget or [])
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "AXS({})".format(
|
return "AXS({})".format(
|
||||||
", ".join(
|
", ".join(
|
||||||
"{}={!r}".format(k, self.__dict__[k])
|
"{}={!r}".format(k, self.__dict__[k])
|
||||||
for k in "uread uwrite umove udel uget".split()
|
for k in "uread uwrite umove udel uget upget".split()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -293,6 +295,7 @@ class VFS(object):
|
||||||
self.amove: dict[str, list[str]] = {}
|
self.amove: dict[str, list[str]] = {}
|
||||||
self.adel: dict[str, list[str]] = {}
|
self.adel: dict[str, list[str]] = {}
|
||||||
self.aget: dict[str, list[str]] = {}
|
self.aget: dict[str, list[str]] = {}
|
||||||
|
self.apget: dict[str, list[str]] = {}
|
||||||
|
|
||||||
if realpath:
|
if realpath:
|
||||||
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
||||||
|
@ -384,8 +387,10 @@ class VFS(object):
|
||||||
|
|
||||||
return self, vpath
|
return self, vpath
|
||||||
|
|
||||||
def can_access(self, vpath: str, uname: str) -> tuple[bool, bool, bool, bool, bool]:
|
def can_access(
|
||||||
"""can Read,Write,Move,Delete,Get"""
|
self, vpath: str, uname: str
|
||||||
|
) -> tuple[bool, bool, bool, bool, bool, bool]:
|
||||||
|
"""can Read,Write,Move,Delete,Get,Upget"""
|
||||||
vn, _ = self._find(vpath)
|
vn, _ = self._find(vpath)
|
||||||
c = vn.axs
|
c = vn.axs
|
||||||
return (
|
return (
|
||||||
|
@ -394,6 +399,7 @@ class VFS(object):
|
||||||
uname in c.umove or "*" in c.umove,
|
uname in c.umove or "*" in c.umove,
|
||||||
uname in c.udel or "*" in c.udel,
|
uname in c.udel or "*" in c.udel,
|
||||||
uname in c.uget or "*" in c.uget,
|
uname in c.uget or "*" in c.uget,
|
||||||
|
uname in c.upget or "*" in c.upget,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(
|
def get(
|
||||||
|
@ -728,7 +734,7 @@ class AuthSrv(object):
|
||||||
def _read_vol_str(
|
def _read_vol_str(
|
||||||
self, lvl: str, uname: str, axs: AXS, flags: dict[str, Any]
|
self, lvl: str, uname: str, axs: AXS, flags: dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
if lvl.strip("crwmdg"):
|
if lvl.strip("crwmdgG"):
|
||||||
raise Exception("invalid volflag: {},{}".format(lvl, uname))
|
raise Exception("invalid volflag: {},{}".format(lvl, uname))
|
||||||
|
|
||||||
if lvl == "c":
|
if lvl == "c":
|
||||||
|
@ -758,7 +764,9 @@ class AuthSrv(object):
|
||||||
("m", axs.umove),
|
("m", axs.umove),
|
||||||
("d", axs.udel),
|
("d", axs.udel),
|
||||||
("g", axs.uget),
|
("g", axs.uget),
|
||||||
]:
|
("G", axs.uget),
|
||||||
|
("G", axs.upget),
|
||||||
|
]: # b bb bbb
|
||||||
if ch in lvl:
|
if ch in lvl:
|
||||||
al.add(un)
|
al.add(un)
|
||||||
|
|
||||||
|
@ -808,7 +816,7 @@ class AuthSrv(object):
|
||||||
|
|
||||||
if self.args.v:
|
if self.args.v:
|
||||||
# list of src:dst:permset:permset:...
|
# list of src:dst:permset:permset:...
|
||||||
# permset is <rwmdg>[,username][,username] or <c>,<flag>[=args]
|
# permset is <rwmdgG>[,username][,username] or <c>,<flag>[=args]
|
||||||
for v_str in self.args.v:
|
for v_str in self.args.v:
|
||||||
m = re_vol.match(v_str)
|
m = re_vol.match(v_str)
|
||||||
if not m:
|
if not m:
|
||||||
|
@ -873,7 +881,7 @@ class AuthSrv(object):
|
||||||
vfs.all_vols = {}
|
vfs.all_vols = {}
|
||||||
vfs.get_all_vols(vfs.all_vols)
|
vfs.get_all_vols(vfs.all_vols)
|
||||||
|
|
||||||
for perm in "read write move del get".split():
|
for perm in "read write move del get pget".split():
|
||||||
axs_key = "u" + perm
|
axs_key = "u" + perm
|
||||||
unames = ["*"] + list(acct.keys())
|
unames = ["*"] + list(acct.keys())
|
||||||
umap: dict[str, list[str]] = {x: [] for x in unames}
|
umap: dict[str, list[str]] = {x: [] for x in unames}
|
||||||
|
@ -888,7 +896,7 @@ class AuthSrv(object):
|
||||||
all_users = {}
|
all_users = {}
|
||||||
missing_users = {}
|
missing_users = {}
|
||||||
for axs in daxs.values():
|
for axs in daxs.values():
|
||||||
for d in [axs.uread, axs.uwrite, axs.umove, axs.udel, axs.uget]:
|
for d in [axs.uread, axs.uwrite, axs.umove, axs.udel, axs.uget, axs.upget]:
|
||||||
for usr in d:
|
for usr in d:
|
||||||
all_users[usr] = 1
|
all_users[usr] = 1
|
||||||
if usr != "*" and usr not in acct:
|
if usr != "*" and usr not in acct:
|
||||||
|
@ -1193,6 +1201,7 @@ class AuthSrv(object):
|
||||||
[" move", "umove"],
|
[" move", "umove"],
|
||||||
["delete", "udel"],
|
["delete", "udel"],
|
||||||
[" get", "uget"],
|
[" get", "uget"],
|
||||||
|
[" upget", "upget"],
|
||||||
]:
|
]:
|
||||||
u = list(sorted(getattr(zv.axs, attr)))
|
u = list(sorted(getattr(zv.axs, attr)))
|
||||||
u = ", ".join("\033[35meverybody\033[0m" if x == "*" else x for x in u)
|
u = ", ".join("\033[35meverybody\033[0m" if x == "*" else x for x in u)
|
||||||
|
@ -1288,10 +1297,11 @@ class AuthSrv(object):
|
||||||
raise Exception("volume not found: " + zs)
|
raise Exception("volume not found: " + zs)
|
||||||
|
|
||||||
self.log(str({"users": users, "vols": vols, "flags": flags}))
|
self.log(str({"users": users, "vols": vols, "flags": flags}))
|
||||||
t = "/{}: read({}) write({}) move({}) del({}) get({})"
|
t = "/{}: read({}) write({}) move({}) del({}) get({}) upget({})"
|
||||||
for k, zv in self.vfs.all_vols.items():
|
for k, zv in self.vfs.all_vols.items():
|
||||||
vc = zv.axs
|
vc = zv.axs
|
||||||
self.log(t.format(k, vc.uread, vc.uwrite, vc.umove, vc.udel, vc.uget))
|
vs = [k, vc.uread, vc.uwrite, vc.umove, vc.udel, vc.uget, vc.upget]
|
||||||
|
self.log(t.format(*vs))
|
||||||
|
|
||||||
flag_v = "v" in flags
|
flag_v = "v" in flags
|
||||||
flag_ln = "ln" in flags
|
flag_ln = "ln" in flags
|
||||||
|
|
|
@ -94,6 +94,9 @@ class FtpFs(AbstractedFS):
|
||||||
self.cwd = "/" # pyftpdlib convention of leading slash
|
self.cwd = "/" # pyftpdlib convention of leading slash
|
||||||
self.root = "/var/lib/empty"
|
self.root = "/var/lib/empty"
|
||||||
|
|
||||||
|
self.can_read = self.can_write = self.can_move = False
|
||||||
|
self.can_delete = self.can_get = self.can_upget = False
|
||||||
|
|
||||||
self.listdirinfo = self.listdir
|
self.listdirinfo = self.listdir
|
||||||
self.chdir(".")
|
self.chdir(".")
|
||||||
|
|
||||||
|
@ -153,8 +156,14 @@ class FtpFs(AbstractedFS):
|
||||||
|
|
||||||
def chdir(self, path: str) -> None:
|
def chdir(self, path: str) -> None:
|
||||||
self.cwd = join(self.cwd, path)
|
self.cwd = join(self.cwd, path)
|
||||||
x = self.hub.asrv.vfs.can_access(self.cwd.lstrip("/"), self.h.username)
|
(
|
||||||
self.can_read, self.can_write, self.can_move, self.can_delete, self.can_get = x
|
self.can_read,
|
||||||
|
self.can_write,
|
||||||
|
self.can_move,
|
||||||
|
self.can_delete,
|
||||||
|
self.can_get,
|
||||||
|
self.can_upget,
|
||||||
|
) = self.hub.asrv.vfs.can_access(self.cwd.lstrip("/"), self.h.username)
|
||||||
|
|
||||||
def mkdir(self, path: str) -> None:
|
def mkdir(self, path: str) -> None:
|
||||||
ap = self.rv2a(path, w=True)
|
ap = self.rv2a(path, w=True)
|
||||||
|
|
|
@ -147,6 +147,7 @@ class HttpCli(object):
|
||||||
self.can_move = False
|
self.can_move = False
|
||||||
self.can_delete = False
|
self.can_delete = False
|
||||||
self.can_get = False
|
self.can_get = False
|
||||||
|
self.can_upget = False
|
||||||
# post
|
# post
|
||||||
self.parser: Optional[MultipartParser] = None
|
self.parser: Optional[MultipartParser] = None
|
||||||
# end placeholders
|
# end placeholders
|
||||||
|
@ -363,6 +364,7 @@ class HttpCli(object):
|
||||||
self.mvol = self.asrv.vfs.amove[self.uname]
|
self.mvol = self.asrv.vfs.amove[self.uname]
|
||||||
self.dvol = self.asrv.vfs.adel[self.uname]
|
self.dvol = self.asrv.vfs.adel[self.uname]
|
||||||
self.gvol = self.asrv.vfs.aget[self.uname]
|
self.gvol = self.asrv.vfs.aget[self.uname]
|
||||||
|
self.upvol = self.asrv.vfs.apget[self.uname]
|
||||||
|
|
||||||
if pwd:
|
if pwd:
|
||||||
self.out_headerlist.append(("Set-Cookie", self.get_pwd_cookie(pwd)[0]))
|
self.out_headerlist.append(("Set-Cookie", self.get_pwd_cookie(pwd)[0]))
|
||||||
|
@ -376,8 +378,14 @@ class HttpCli(object):
|
||||||
ptn: Optional[Pattern[str]] = self.conn.lf_url # mypy404
|
ptn: Optional[Pattern[str]] = self.conn.lf_url # mypy404
|
||||||
self.do_log = not ptn or not ptn.search(self.req)
|
self.do_log = not ptn or not ptn.search(self.req)
|
||||||
|
|
||||||
x = self.asrv.vfs.can_access(self.vpath, self.uname)
|
(
|
||||||
self.can_read, self.can_write, self.can_move, self.can_delete, self.can_get = x
|
self.can_read,
|
||||||
|
self.can_write,
|
||||||
|
self.can_move,
|
||||||
|
self.can_delete,
|
||||||
|
self.can_get,
|
||||||
|
self.can_upget,
|
||||||
|
) = self.asrv.vfs.can_access(self.vpath, self.uname)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.mode in ["GET", "HEAD"]:
|
if self.mode in ["GET", "HEAD"]:
|
||||||
|
@ -885,7 +893,7 @@ class HttpCli(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
vsuf = ""
|
vsuf = ""
|
||||||
if self.can_read and "fk" in vfs.flags:
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
||||||
vsuf = "?k=" + self.gen_fk(
|
vsuf = "?k=" + self.gen_fk(
|
||||||
self.args.fk_salt,
|
self.args.fk_salt,
|
||||||
path,
|
path,
|
||||||
|
@ -1544,7 +1552,7 @@ class HttpCli(object):
|
||||||
|
|
||||||
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
||||||
vsuf = ""
|
vsuf = ""
|
||||||
if self.can_read and "fk" in vfs.flags:
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
||||||
vsuf = "?k=" + self.gen_fk(
|
vsuf = "?k=" + self.gen_fk(
|
||||||
self.args.fk_salt,
|
self.args.fk_salt,
|
||||||
ap,
|
ap,
|
||||||
|
@ -2494,9 +2502,8 @@ class HttpCli(object):
|
||||||
|
|
||||||
if not is_dir and (self.can_read or self.can_get):
|
if not is_dir and (self.can_read or self.can_get):
|
||||||
if not self.can_read and "fk" in vn.flags:
|
if not self.can_read and "fk" in vn.flags:
|
||||||
vabs = vjoin(vn.realpath, rem)
|
|
||||||
correct = self.gen_fk(
|
correct = self.gen_fk(
|
||||||
self.args.fk_salt, vabs, st.st_size, 0 if ANYWIN else st.st_ino
|
self.args.fk_salt, abspath, st.st_size, 0 if ANYWIN else st.st_ino
|
||||||
)[: vn.flags["fk"]]
|
)[: vn.flags["fk"]]
|
||||||
got = self.uparam.get("k")
|
got = self.uparam.get("k")
|
||||||
if got != correct:
|
if got != correct:
|
||||||
|
@ -2541,6 +2548,8 @@ class HttpCli(object):
|
||||||
perms.append("delete")
|
perms.append("delete")
|
||||||
if self.can_get:
|
if self.can_get:
|
||||||
perms.append("get")
|
perms.append("get")
|
||||||
|
if self.can_upget:
|
||||||
|
perms.append("upget")
|
||||||
|
|
||||||
url_suf = self.urlq({}, ["k"])
|
url_suf = self.urlq({}, ["k"])
|
||||||
is_ls = "ls" in self.uparam
|
is_ls = "ls" in self.uparam
|
||||||
|
|
|
@ -422,7 +422,7 @@ class SvcHub(object):
|
||||||
|
|
||||||
with self.log_mutex:
|
with self.log_mutex:
|
||||||
ts = datetime.utcnow().strftime("%Y-%m%d-%H%M%S.%f")[:-3]
|
ts = datetime.utcnow().strftime("%Y-%m%d-%H%M%S.%f")[:-3]
|
||||||
self.logf.write("@{} [{}] {}\n".format(ts, src, msg))
|
self.logf.write("@{} [{}\033[0m] {}\n".format(ts, src, msg))
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now >= self.next_day:
|
if now >= self.next_day:
|
||||||
|
|
Loading…
Reference in a new issue