diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 60bb6919..21371443 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -395,7 +395,7 @@ def configure_ssl_ciphers(al: argparse.Namespace) -> None: def args_from_cfg(cfg_path: str) -> list[str]: lines: list[str] = [] - expand_config_file(lines, cfg_path, "") + expand_config_file(None, lines, cfg_path, "") lines = upgrade_cfg_fmt(None, argparse.Namespace(vc=False), lines, "") ret: list[str] = [] diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index df945b63..cf7b066a 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -863,7 +863,7 @@ class AuthSrv(object): ) -> None: self.line_ctr = 0 - expand_config_file(cfg_lines, fp, "") + expand_config_file(self.log, cfg_lines, fp, "") if self.args.vc: lns = ["{:4}: {}".format(n, s) for n, s in enumerate(cfg_lines, 1)] self.log("expanded config file (unprocessed):\n" + "\n".join(lns)) @@ -2101,27 +2101,47 @@ def split_cfg_ln(ln: str) -> dict[str, Any]: return ret -def expand_config_file(ret: list[str], fp: str, ipath: str) -> None: +def expand_config_file(log: Optional["NamedLogger"], ret: list[str], fp: str, ipath: str) -> None: """expand all % file includes""" fp = absreal(fp) if len(ipath.split(" -> ")) > 64: raise Exception("hit max depth of 64 includes") if os.path.isdir(fp): - names = os.listdir(fp) - crumb = "#\033[36m cfg files in {} => {}\033[0m".format(fp, names) - ret.append(crumb) - for fn in sorted(names): + names = list(sorted(os.listdir(fp))) + cnames = [x for x in names if x.lower().endswith(".conf")] + if not cnames: + t = "warning: tried to read config-files from folder '%s' but it does not contain any " + if names: + t += ".conf files; the following files were ignored: %s" + t = t % (fp, ", ".join(names[:8])) + else: + t += "files at all" + t = t % (fp,) + + if log: + log(t, 3) + + ret.append("#\033[33m %s\033[0m" % (t,)) + else: + zs = "#\033[36m cfg files in %s => %s\033[0m" % (fp, cnames) + ret.append(zs) + + for fn in cnames: fp2 = os.path.join(fp, fn) - if not fp2.endswith(".conf") or fp2 in ipath: + if fp2 in ipath: continue - expand_config_file(ret, fp2, ipath) + expand_config_file(log, ret, fp2, ipath) - if ret[-1] == crumb: - # no config files below; remove breadcrumb - ret.pop() + return + if not os.path.exists(fp): + t = "warning: tried to read config from '%s' but the file/folder does not exist" % (fp,) + if log: + log(t, 3) + + ret.append("#\033[31m %s\033[0m" % (t,)) return ipath += " -> " + fp @@ -2135,7 +2155,7 @@ def expand_config_file(ret: list[str], fp: str, ipath: str) -> None: fp2 = ln[1:].strip() fp2 = os.path.join(os.path.dirname(fp), fp2) ofs = len(ret) - expand_config_file(ret, fp2, ipath) + expand_config_file(log, ret, fp2, ipath) for n in range(ofs, len(ret)): ret[n] = pad + ret[n] continue diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 88b7c215..0cf531ed 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -518,9 +518,13 @@ class HttpCli(object): return self.handle_options() and self.keepalive if not cors_k: + host = self.headers.get("host", "") origin = self.headers.get("origin", "") - self.log("cors-reject {} from {}".format(self.mode, origin), 3) - raise Pebkac(403, "no surfing") + proto = "https://" if self.is_https else "http://" + guess = "modifying" if (origin and host) else "stripping" + t = "cors-reject %s because request-header Origin='%s' does not match request-protocol '%s' and host '%s' based on request-header Host='%s' (note: if this request is not malicious, check if your reverse-proxy is accidentally %s request headers, in particular 'Origin', for example by running copyparty with --ihead='*' to show all request headers)" + self.log(t % (self.mode, origin, proto, self.host, host, guess), 3) + raise Pebkac(403, "rejected by cors-check") # getattr(self.mode) is not yet faster than this if self.mode == "POST": diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 008cf5eb..223d8afd 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -28,7 +28,7 @@ if True: # pylint: disable=using-constant-test import typing from typing import Any, Optional, Union -from .__init__ import ANYWIN, EXE, MACOS, TYPE_CHECKING, EnvParams, unicode +from .__init__ import ANYWIN, E, EXE, MACOS, TYPE_CHECKING, EnvParams, unicode from .authsrv import BAD_CFG, AuthSrv from .cert import ensure_cert from .mtag import HAVE_FFMPEG, HAVE_FFPROBE @@ -154,6 +154,8 @@ class SvcHub(object): lg.handlers = [lh] lg.setLevel(logging.DEBUG) + self._check_env() + if args.stackmon: start_stackmon(args.stackmon, 0) @@ -385,6 +387,17 @@ class SvcHub(object): Daemon(self.sd_notify, "sd-notify") + def _check_env(self) -> None: + try: + files = os.listdir(E.cfg) + except: + files = [] + + hits = [x for x in files if x.lower().endswith(".conf")] + if hits: + t = "WARNING: found config files in [%s]: %s\n config files are not expected here, and will NOT be loaded (unless your setup is intentionally hella funky)" + self.log("root", t % (E.cfg, ", ".join(hits)), 3) + def _process_config(self) -> bool: al = self.args diff --git a/copyparty/web/util.js b/copyparty/web/util.js index 1faf73be..f654a0a6 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -1995,15 +1995,19 @@ function xhrchk(xhr, prefix, e404, lvl, tag) { if (tag === undefined) tag = prefix; - var errtxt = (xhr.response && xhr.response.err) || xhr.responseText, + var errtxt = ((xhr.response && xhr.response.err) || xhr.responseText) || '', + suf = '', fun = toast[lvl || 'err'], is_cf = /[Cc]loud[f]lare|>Just a mo[m]ent|#cf-b[u]bbles|Chec[k]ing your br[o]wser|\/chall[e]nge-platform|"chall[e]nge-error|nable Ja[v]aScript and cook/.test(errtxt); + if (errtxt.startsWith('
'))
+        suf = '\n\nerror-details: «' + errtxt.slice(5).split('\n')[0].trim() + '»';
+
     if (xhr.status == 403 && !is_cf)
-        return toast.err(0, prefix + (L && L.xhr403 || "403: access denied\n\ntry pressing F5, maybe you got logged out"), tag);
+        return toast.err(0, prefix + (L && L.xhr403 || "403: access denied\n\ntry pressing F5, maybe you got logged out") + suf, tag);
 
     if (xhr.status == 404)
-        return toast.err(0, prefix + e404, tag);
+        return toast.err(0, prefix + e404 + suf, tag);
 
     if (is_cf && (xhr.status == 403 || xhr.status == 503)) {
         var now = Date.now(), td = now - cf_cha_t;