diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 156fbee4..eb8211c2 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -11,12 +11,13 @@ import hashlib import threading from datetime import datetime -from .__init__ import WINDOWS +from .__init__ import ANYWIN, WINDOWS from .util import ( IMPLICATIONS, META_NOBOTS, uncyg, undot, + relchk, unhumanize, absreal, Pebkac, @@ -335,6 +336,12 @@ class VFS(object): ): # type: (str, str, bool, bool, bool, bool, bool) -> tuple[VFS, str] """returns [vfsnode,fs_remainder] if user has the requested permissions""" + if ANYWIN: + mod = relchk(vpath) + if mod: + self.log("vfs", "invalid relpath [{}]".format(vpath)) + raise Pebkac(404) + vn, rem = self._find(vpath) c = vn.axs diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 34b82d7b..2f5ad171 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -210,6 +210,11 @@ class HttpCli(object): self.uparam = uparam self.cookies = cookies self.vpath = unquotep(vpath) # not query, so + means + + if ANYWIN: + mod = relchk(self.vpath) + if mod: + self.log("invalid relpath [{}]".format(self.vpath)) + return self.tx_404() and self.keepalive pwd = None ba = self.headers.get("authorization") @@ -1046,6 +1051,7 @@ class HttpCli(object): raise Pebkac(500, min_ex()) vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/") + self.out_headers["X-New-Dir"] = quotep(sanitized) self.redirect(vpath) return True diff --git a/copyparty/util.py b/copyparty/util.py index b56f9a1b..3dcdfe85 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -912,6 +912,9 @@ def sanitize_fn(fn, ok, bad): if "/" not in ok: fn = fn.replace("\\", "/").split("/")[-1] + if fn.lower() in bad: + fn = "_" + fn + if ANYWIN: remap = [ ["<", "<"], @@ -927,16 +930,23 @@ def sanitize_fn(fn, ok, bad): for a, b in [x for x in remap if x[0] not in ok]: fn = fn.replace(a, b) - bad.extend(["con", "prn", "aux", "nul"]) + bad = ["con", "prn", "aux", "nul"] for n in range(1, 10): bad += "com{0} lpt{0}".format(n).split(" ") - if fn.lower() in bad: - fn = "_" + fn + if fn.lower().split(".")[0] in bad: + fn = "_" + fn return fn.strip() +def relchk(rp): + if ANYWIN: + p = re.sub(r'[\\:*?"<>|]', "", rp) + if p != rp: + return p + + def absreal(fpath): try: return fsdec(os.path.abspath(os.path.realpath(fsenc(fpath)))) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 27dbdb5e..36d471d4 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -4903,7 +4903,10 @@ var msel = (function () { tb.value = ''; clmod(sf, 'vis'); sf.textContent = ''; - treectl.goto(this.vp + uricom_enc(this.dn) + '/', true); + + var dn = this.getResponseHeader('X-New-Dir'); + dn = dn || uricom_enc(this.dn); + treectl.goto(this.vp + dn + '/', true); } })();