From d3b9599421a2ac21ce4acf90a7dad17efb1b0019 Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 29 Jun 2026 19:26:01 +0000 Subject: [PATCH] csp script nonce --- contrib/plugins/minimal-up2k.js | 5 +++- copyparty/__init__.py | 1 - copyparty/__main__.py | 6 ++-- copyparty/authsrv.py | 13 ++++++--- copyparty/cfg.py | 4 +++ copyparty/httpcli.py | 18 ++++++++---- copyparty/web/browser.html | 17 ++++++----- copyparty/web/browser.js | 37 +++++++++++++++-------- copyparty/web/cf.html | 2 +- copyparty/web/idp.html | 9 +++--- copyparty/web/md.html | 15 +++++----- copyparty/web/mde.html | 15 +++++----- copyparty/web/msg.html | 6 ++-- copyparty/web/rups.html | 13 +++++---- copyparty/web/shares.html | 11 +++---- copyparty/web/splash.html | 20 ++++++++----- copyparty/web/svcs.html | 11 +++---- copyparty/web/tl/chi.js | 2 +- copyparty/web/tl/cze.js | 2 +- copyparty/web/tl/deu.js | 2 +- copyparty/web/tl/epo.js | 2 +- copyparty/web/tl/fin.js | 2 +- copyparty/web/tl/fra.js | 2 +- copyparty/web/tl/grc.js | 2 +- copyparty/web/tl/hun.js | 2 +- copyparty/web/tl/ita.js | 2 +- copyparty/web/tl/jpn.js | 2 +- copyparty/web/tl/kor.js | 2 +- copyparty/web/tl/nld.js | 2 +- copyparty/web/tl/nno.js | 2 +- copyparty/web/tl/nor.js | 2 +- copyparty/web/tl/pol.js | 2 +- copyparty/web/tl/por.js | 2 +- copyparty/web/tl/rus.js | 2 +- copyparty/web/tl/spa.js | 2 +- copyparty/web/tl/swe.js | 2 +- copyparty/web/tl/tur.js | 2 +- copyparty/web/tl/ukr.js | 2 +- copyparty/web/tl/vie.js | 2 +- copyparty/web/up2k.js | 52 +++++++++++++++++++++++---------- copyparty/web/util.js | 19 +++++++++--- copyparty/web/w.hash.js | 15 +++++----- scripts/deps-docker/Dockerfile | 4 ++- scripts/make-sfx.sh | 25 ++++++++++++++-- scripts/sfx.ls | 1 - scripts/tl.js | 2 +- tests/util.py | 4 +-- 47 files changed, 235 insertions(+), 134 deletions(-) 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 = '' + html + - '' + sandboxjs() + - '' + sandboxjs() + + ' - + {%- if js %} - + {%- endif %} - diff --git a/copyparty/web/md.html b/copyparty/web/md.html index 65deec1e..8913b5c4 100644 --- a/copyparty/web/md.html +++ b/copyparty/web/md.html @@ -131,9 +131,10 @@ write markdown (most html is 🙆 too) {%- endif %} - - - - + + + {%- if edit %} - + {%- endif %} - {%- if js %} - + {%- endif %} diff --git a/copyparty/web/mde.html b/copyparty/web/mde.html index 1065e74d..80909653 100644 --- a/copyparty/web/mde.html +++ b/copyparty/web/mde.html @@ -28,9 +28,10 @@ π - - - - - + + + + {%- if js %} - + {%- endif %} - + {%- endif %} {%- if redir %} - {%- endif %} {%- if js %} - + {%- endif %} diff --git a/copyparty/web/rups.html b/copyparty/web/rups.html index f2ad0de7..50b2cbce 100644 --- a/copyparty/web/rups.html +++ b/copyparty/web/rups.html @@ -22,9 +22,10 @@
π - - - - + + + {%- if js %} - + {%- endif %} - - - + + {%- if js %} - + {%- endif %} - - + {%- if lang != "eng" %} - + {%- endif %} - + {%- if js %} - + {%- endif %} - - - + + {%- if js %} - + {%- endif %} -