diff --git a/contrib/plugins/minimal-up2k.js b/contrib/plugins/minimal-up2k.js index b3514aea..e3defcd8 100644 --- a/contrib/plugins/minimal-up2k.js +++ b/contrib/plugins/minimal-up2k.js @@ -66,11 +66,14 @@ var u2min = ` -show advanced options +show advanced options `; if (!has(perms, 'read')) { var e2 = mknod('div'); e2.innerHTML = u2min; ebi('wrap').insertBefore(e2, QS('#wfp')); + ebi('u2min_off').onclick = function () { + this.parentNode.innerHTML=''; + }; } diff --git a/copyparty/__init__.py b/copyparty/__init__.py index 6430e655..6756b8b5 100644 --- a/copyparty/__init__.py +++ b/copyparty/__init__.py @@ -135,7 +135,6 @@ web/tl/vie.js web/ui.css web/up2k.js web/util.js -web/w.hash.js """ RES = set(zs.strip().split("\n")) RESM = { diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 7fdb81ec..af0df4af 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1681,7 +1681,9 @@ def add_safety(ap): ap2.add_argument("--no-dot-ren", action="store_true", help="disallow renaming dotfiles; makes it impossible to turn something into a dotfile") ap2.add_argument("--no-logues", action="store_true", help="disable rendering .prologue/.epilogue.html into directory listings") ap2.add_argument("--no-readme", action="store_true", help="disable rendering readme/preadme.md into directory listings") - ap2.add_argument("--no-script", action="store_true", help="disables javascript in html files; helps prevent XSS but kills interactive websites (volflag=noscript)") + ap2.add_argument("--csp-ui", metavar="TXT", default="script-src 'unsafe-eval' 'nonce-{{ js_nonce }}'; worker-src 'self'", help="content-security-policy to apply for the web-UI; default helps prevent XSS by blocking \n" + self.html_head += ( + '\n' + ) else: - self.html_head += "\n" + self.html_head += ( + '\n' + ) zs = self.asrv.ases.get(idp_usr) if zs: self.set_idp_cookie(zs) @@ -1115,7 +1122,7 @@ class HttpCli(object): self.cbonk(self.conn.hsrv.gmal, zs, "cc_hdr", "Cc in out-hdr") raise Pebkac(999) - response.append(self.vn.flags[oh_k]) + response.append(self.vn.flags[oh_k].replace("{{ js_nonce }}", self.js_nonce)) if self.args.ohead and self.do_log: zs = response.pop()[:-4] @@ -5374,7 +5381,7 @@ class HttpCli(object): file_ts = int(max(ts_md, self.E.t0)) file_lastmod, do_send, _ = self._chk_lastmod(file_ts) self.out_headers["Last-Modified"] = file_lastmod - self.out_headers["Cache-Control"] = "no-cache" + # default Cache-Control (no-store) due to csp nonce status = 200 if do_send else 304 arg_base = "?" @@ -5384,6 +5391,7 @@ class HttpCli(object): boundary = "\roll\tide" targs = { "r": self.args.SR if self.is_vproxied else "", + "js_nonce": self.js_nonce, "ts": self.conn.hsrv.cachebuster(), "edit": "edit" in self.uparam, "title": html_escape(self.vpath, crlf=True), diff --git a/copyparty/web/browser.html b/copyparty/web/browser.html index a5b412b0..61a37526 100644 --- a/copyparty/web/browser.html +++ b/copyparty/web/browser.html @@ -131,8 +131,9 @@
- - + {%- if lang != "eng" %} - + {%- endif %} - - - + + + {%- if js %} - + {%- endif %} - '; + tag = ''; return function () { if (ret || busy) @@ -9128,7 +9140,7 @@ var sandboxjs = (function () { xhr.open('GET', url, true); xhr.onload = function () { if (this.status == 200) - ret = ''; + ret = ''; }; xhr.send(); busy = true; @@ -9276,8 +9288,9 @@ function sandbox(tgt, rules, allow, cls, html) { html = '