Skip to content

Commit 9ae5e46

Browse files
committed
merge: WebUI modernization stack (PR2-PR7, phases 2b-4)
2 parents e5eb464 + c3991d2 commit 9ae5e46

19 files changed

Lines changed: 3261 additions & 2102 deletions

.github/workflows/test.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ jobs:
4848
version: v2.12.2
4949
args: --timeout=10m
5050

51+
ui-js:
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@v4
55+
56+
- uses: actions/setup-node@v4
57+
with:
58+
node-version: "22"
59+
60+
- name: test
61+
run: node --test "cmd/odek/ui/js/**/*.test.js"
62+
5163
vuln:
5264
runs-on: ubuntu-latest
5365
steps:

cmd/odek/serve.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,17 @@ func handleStatic(wsToken string) http.HandlerFunc {
17621762
return
17631763
}
17641764
entry, ok := staticFiles[r.URL.Path]
1765+
if !ok && strings.HasPrefix(r.URL.Path, "/js/") {
1766+
// ES modules under /js/ are served from the embedded ui/js
1767+
// directory. Sanitize to a flat .js file name so path traversal
1768+
// is impossible.
1769+
name := strings.TrimPrefix(r.URL.Path, "/js/")
1770+
if name != "" && !strings.Contains(name, "..") &&
1771+
!strings.ContainsAny(name, "/\\") && strings.HasSuffix(name, ".js") {
1772+
entry = [2]string{"ui/js/" + name, "application/javascript; charset=utf-8"}
1773+
ok = true
1774+
}
1775+
}
17651776
if !ok {
17661777
http.NotFound(w, r)
17671778
return
@@ -1809,7 +1820,10 @@ func handleStatic(wsToken string) http.HandlerFunc {
18091820
w.Header().Set("X-Content-Type-Options", "nosniff")
18101821
w.Header().Set("Referrer-Policy", "no-referrer")
18111822
w.Header().Set("X-Frame-Options", "DENY")
1812-
w.Header().Set("Content-Security-Policy", "frame-ancestors 'none'")
1823+
// Strict CSP: no inline scripts (all handlers are addEventListener /
1824+
// delegation), styles only from self + the few style="" attributes in
1825+
// index.html. frame-ancestors replaces the old standalone CSP line.
1826+
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'none'; form-action 'none'")
18131827
w.Write(data)
18141828
}
18151829
}

0 commit comments

Comments
 (0)