also mkdir missing intermediates,

unless requester is a webdav client (those expect a 409)
This commit is contained in:
ed 2023-11-03 23:23:49 +00:00
parent 8020b11ea0
commit 713fffcb8e
4 changed files with 21 additions and 11 deletions

View file

@ -498,8 +498,8 @@ class VFS(object):
t = "{} has no {} in [{}] => [{}] => [{}]" t = "{} has no {} in [{}] => [{}] => [{}]"
self.log("vfs", t.format(uname, msg, vpath, cvpath, ap), 6) self.log("vfs", t.format(uname, msg, vpath, cvpath, ap), 6)
t = "you don't have {}-access for this location" t = 'you don\'t have %s-access in "/%s"'
raise Pebkac(err, t.format(msg)) raise Pebkac(err, t % (msg, cvpath))
return vn, rem return vn, rem

View file

@ -2175,26 +2175,30 @@ class HttpCli(object):
new_dir = self.parser.require("name", 512) new_dir = self.parser.require("name", 512)
self.parser.drop() self.parser.drop()
sanitized = sanitize_fn(new_dir, "", []) return self._mkdir(vjoin(self.vpath, new_dir))
return self._mkdir(vjoin(self.vpath, sanitized))
def _mkdir(self, vpath: str, dav: bool = False) -> bool: def _mkdir(self, vpath: str, dav: bool = False) -> bool:
nullwrite = self.args.nw nullwrite = self.args.nw
self.gctx = vpath
vpath = undot(vpath)
vfs, rem = self.asrv.vfs.get(vpath, self.uname, False, True) vfs, rem = self.asrv.vfs.get(vpath, self.uname, False, True)
self._assert_safe_rem(rem) rem = sanitize_vpath(rem, "/", [])
fn = vfs.canonical(rem) fn = vfs.canonical(rem)
if not fn.startswith(vfs.realpath):
self.log("invalid mkdir [%s] [%s]" % (self.gctx, vpath), 1)
raise Pebkac(422)
if not nullwrite: if not nullwrite:
fdir = os.path.dirname(fn) fdir = os.path.dirname(fn)
if not bos.path.isdir(fdir): if dav and not bos.path.isdir(fdir):
raise Pebkac(409, "parent folder does not exist") raise Pebkac(409, "parent folder does not exist")
if bos.path.isdir(fn): if bos.path.isdir(fn):
raise Pebkac(405, "that folder exists already") raise Pebkac(405, 'folder "/%s" already exists' % (vpath,))
try: try:
bos.mkdir(fn) bos.makedirs(fn)
except OSError as ex: except OSError as ex:
if ex.errno == errno.EACCES: if ex.errno == errno.EACCES:
raise Pebkac(500, "the server OS denied write-access") raise Pebkac(500, "the server OS denied write-access")
@ -2203,7 +2207,7 @@ class HttpCli(object):
except: except:
raise Pebkac(500, min_ex()) raise Pebkac(500, min_ex())
self.out_headers["X-New-Dir"] = quotep(vpath.split("/")[-1]) self.out_headers["X-New-Dir"] = quotep(vpath)
if dav: if dav:
self.reply(b"", 201) self.reply(b"", 201)

View file

@ -1773,6 +1773,12 @@ def sanitize_fn(fn: str, ok: str, bad: list[str]) -> str:
return fn.strip() return fn.strip()
def sanitize_vpath(vp: str, ok: str, bad: list[str]) -> str:
parts = vp.replace(os.sep, "/").split("/")
ret = [sanitize_fn(x, ok, bad) for x in parts]
return "/".join(ret)
def relchk(rp: str) -> str: def relchk(rp: str) -> str:
if "\x00" in rp: if "\x00" in rp:
return "[nul]" return "[nul]"

View file

@ -7200,8 +7200,8 @@ var msel = (function () {
sf.textContent = ''; sf.textContent = '';
var dn = this.getResponseHeader('X-New-Dir'); var dn = this.getResponseHeader('X-New-Dir');
dn = dn || uricom_enc(this.dn); dn = dn ? '/' + dn + '/' : uricom_enc(this.dn);
treectl.goto(this.vp + dn + '/', true); treectl.goto(dn, true);
} }
})(); })();