feat(web): switch to the Alpine CSP build; drop 'unsafe-eval' from CSP
Standard Alpine evaluates every attribute expression through new Function(), which a strict Content-Security-Policy cannot allow. Swap to the official CSP-safe build (@alpinejs/csp), whose parser evaluates expressions against registered component scope without eval. script-src now carries only 'self' and 'unsafe-inline' (the latter still required by the pre-paint theme flash guard). Bindings rewritten out of the unsupported expression shapes: - 21 multi-statement sequences across admin, audio_reader, docs, header, index, and reader became single component methods (init/loadWatchStatus hooks, commitScrub, pickSkip, pickSpeed, pickDefaultSpeed, chooseSleepOption, chooseSleepClockMode, toggleFxInvert, openPageThumbs, submitNote, clearSearch, pickReadingTheme) - the header sidebar's inline x-data (openPanel/themeMode IIFE) became a registered sidebarShell component; openPanel itself moved to the header root so every sidebar panel shares one open state - the appearance-panel moved into the component init() - header init() now also seeds openPanel from localStorage (or the admin section on /admin pages) Alpine magics (, , , ) remain available — the CSP evaluator injects them into scope. The Playwright suite covers the converted surfaces end to end.
This commit is contained in:
1 parent
a730a62280
commit
eb57b7208b
15 files changed
+154
-23
No files matched your search
@@ -678,6 +678,31 @@ Alpine.data("audioReader", () => ({
|
||||
})
|
||||
.catch(() => showToast("Default speed not saved", "error"));
|
||||
},
|
||||
// Popover option handlers (CSP-safe: single method calls from templ).
|
||||
commitScrub() {
|
||||
this.seekTo(this.scrubValue);
|
||||
this.scrubbing = false;
|
||||
},
|
||||
pickSkip(seconds: number) {
|
||||
this.setSkip(seconds);
|
||||
this.skipOpen = false;
|
||||
},
|
||||
pickSpeed(rate: number) {
|
||||
this.setSpeed(rate);
|
||||
this.speedOpen = false;
|
||||
},
|
||||
pickDefaultSpeed(rate: number) {
|
||||
this.setDefaultSpeed(rate);
|
||||
this.speedOpen = false;
|
||||
},
|
||||
chooseSleepOption(choice: SleepChoice) {
|
||||
this.chooseSleep(choice);
|
||||
this.sleepOpen = false;
|
||||
},
|
||||
chooseSleepClockMode() {
|
||||
this.chooseSleepClock();
|
||||
this.sleepOpen = false;
|
||||
},
|
||||
|
||||
isDefaultSpeed(rate: number): boolean {
|
||||
return Number(this.defaultSpeed) === rate;
|
||||
|
||||
Reference in new issue
Block a user