diff --git a/copyparty/__main__.py b/copyparty/__main__.py index ac0a395f..fe4f0b51 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -813,7 +813,7 @@ def add_safety(ap, fk_salt): ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 --ban-404=50,60,1440 -nih") ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r") ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m; example [\033[32m**,*,ln,p,r\033[0m]") - ap2.add_argument("--salt", type=u, default="hunter2", help="up2k file-hash salt; used to generate unpredictable internal identifiers for uploads -- doesn't really matter") + ap2.add_argument("--salt", type=u, default="hunter2", help="up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do)") ap2.add_argument("--fk-salt", metavar="SALT", type=u, default=fk_salt, help="per-file accesskey salt; used to generate unpredictable URLs for hidden files -- this one DOES matter") ap2.add_argument("--no-dot-mv", action="store_true", help="disallow moving dotfiles; makes it impossible to move folders containing dotfiles") ap2.add_argument("--no-dot-ren", action="store_true", help="disallow renaming dotfiles; makes it impossible to make something a dotfile") diff --git a/copyparty/ftpd.py b/copyparty/ftpd.py index 3e9f8ff5..bfb42ea0 100644 --- a/copyparty/ftpd.py +++ b/copyparty/ftpd.py @@ -127,6 +127,9 @@ class FtpFs(AbstractedFS): self.listdirinfo = self.listdir self.chdir(".") + def die(self, msg): + self.h.die(msg) + def v2a( self, vpath: str, @@ -140,17 +143,17 @@ class FtpFs(AbstractedFS): rd, fn = os.path.split(vpath) if ANYWIN and relchk(rd): logging.warning("malicious vpath: %s", vpath) - raise FilesystemError("unsupported characters in filepath") + self.die("Unsupported characters in filepath") fn = sanitize_fn(fn or "", "", [".prologue.html", ".epilogue.html"]) vpath = vjoin(rd, fn) vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d) if not vfs.realpath: - raise FilesystemError("no filesystem mounted at this path") + self.die("No filesystem mounted at this path") return os.path.join(vfs.realpath, rem), vfs, rem except Pebkac as ex: - raise FilesystemError(str(ex)) + self.die(str(ex)) def rv2a( self, @@ -173,7 +176,7 @@ class FtpFs(AbstractedFS): def validpath(self, path: str) -> bool: if "/.hist/" in path: if "/up2k." in path or path.endswith("/dir.txt"): - raise FilesystemError("access to this file is forbidden") + self.die("Access to this file is forbidden") return True @@ -190,7 +193,7 @@ class FtpFs(AbstractedFS): td = 0 if td < -1 or td > self.args.ftp_wt: - raise FilesystemError("cannot open existing file for writing") + self.die("Cannot open existing file for writing") self.validpath(ap) return open(fsenc(ap), mode) @@ -201,7 +204,7 @@ class FtpFs(AbstractedFS): ap = vfs.canonical(rem) if not bos.path.isdir(ap): # returning 550 is library-default and suitable - raise FilesystemError("Failed to change directory") + self.die("Failed to change directory") self.cwd = nwd ( @@ -251,28 +254,27 @@ class FtpFs(AbstractedFS): def remove(self, path: str) -> None: if self.args.no_del: - raise FilesystemError("the delete feature is disabled in server config") + self.die("The delete feature is disabled in server config") vp = join(self.cwd, path).lstrip("/") try: - self.hub.up2k.handle_rm(self.uname, self.h.remote_ip, [vp], []) + self.hub.up2k.handle_rm(self.uname, self.h.cli_ip, [vp], []) except Exception as ex: - raise FilesystemError(str(ex)) + self.die(str(ex)) def rename(self, src: str, dst: str) -> None: if not self.can_move: - raise FilesystemError("not allowed for user " + self.h.username) + self.die("Not allowed for user " + self.h.username) if self.args.no_mv: - t = "the rename/move feature is disabled in server config" - raise FilesystemError(t) + self.die("The rename/move feature is disabled in server config") svp = join(self.cwd, src).lstrip("/") dvp = join(self.cwd, dst).lstrip("/") try: self.hub.up2k.handle_mv(self.uname, svp, dvp) except Exception as ex: - raise FilesystemError(str(ex)) + self.die(str(ex)) def chmod(self, path: str, mode: str) -> None: pass @@ -351,6 +353,9 @@ class FtpHandler(FTPHandler): else: super(FtpHandler, self).__init__(conn, server, ioloop) + cip = self.remote_ip + self.cli_ip = cip[7:] if cip.startswith("::ffff:") else cip + # abspath->vpath mapping to resolve log_transfer paths self.vfs_map: dict[str, str] = {} diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 06e67d4b..298807bf 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -1422,7 +1422,7 @@ class HttpCli(object): at, "", ): - t = "upload denied by xbu" + t = "upload blocked by xbu server config" self.log(t, 1) raise Pebkac(403, t) @@ -1499,7 +1499,7 @@ class HttpCli(object): at, "", ): - t = "upload denied by xau" + t = "upload blocked by xau server config" self.log(t, 1) os.unlink(path) raise Pebkac(403, t) @@ -2113,7 +2113,7 @@ class HttpCli(object): at, "", ): - t = "upload denied by xbu" + t = "upload blocked by xbu server config" self.log(t, 1) raise Pebkac(403, t) @@ -2173,7 +2173,7 @@ class HttpCli(object): at, "", ): - t = "upload denied by xau" + t = "upload blocked by xau server config" self.log(t, 1) os.unlink(abspath) raise Pebkac(403, t) diff --git a/copyparty/up2k.py b/copyparty/up2k.py index c38faf99..32a21c89 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -3330,7 +3330,7 @@ class Up2k(object): int(job["t0"]), "", ): - t = "upload blocked by xbu: {}".format(vp_chk) + t = "upload blocked by xbu server config: {}".format(vp_chk) self.log(t, 1) raise Pebkac(403, t) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 585f04de..499d61f9 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -294,6 +294,7 @@ var Ls = { "fd_ok": "delete OK", "fd_err": "delete failed:\n", + "fd_none": "nothing was deleted; maybe blocked by server config (xbd)?", "fd_busy": "deleting {0} items...\n\n{1}", "fd_warn1": "DELETE these {0} items?", "fd_warn2": "Last chance! No way to undo. Delete?", @@ -748,6 +749,7 @@ var Ls = { "fd_ok": "sletting OK", "fd_err": "sletting feilet:\n", + "fd_none": "ingenting ble slettet; kanskje avvist av serverkonfigurasjon (xbd)?", "fd_busy": "sletter {0} filer...\n\n{1}", "fd_warn1": "SLETT disse {0} filene?", "fd_warn2": "Siste sjanse! Dette kan ikke angres. Slett?", @@ -3426,12 +3428,14 @@ var fileman = (function () { if (!sel.length) return toast.err(3, L.fd_emore); - function deleter() { + function deleter(err) { var xhr = new XHR(), vp = vps.shift(); if (!vp) { - toast.ok(2, L.fd_ok); + if (err !== 'xbd') + toast.ok(2, L.fd_ok); + treectl.goto(get_evpath()); return; } @@ -3447,6 +3451,10 @@ var fileman = (function () { toast.err(9, L.fd_err + msg); return; } + if (this.responseText.indexOf('deleted 0 files (and 0') + 1) { + toast.err(9, L.fd_none); + return deleter('xbd'); + } deleter(); }