fix(book-detail): hero backdrop — templ double-escapes style values
templ's codegen wraps style attribute expressions in a sanitizer AND
templ.EscapeString, so any quote character — even inside templ.SafeCSS
— reached the DOM as literal ' text. The hero backdrop's url('...')
never parsed: no blurred cover on any book detail page, and Firefox
resolved the mangled token as a relative URL, fetching /media/& (500)
once per page load.
Fix: emit quote-free CSS — an unquoted url(...) token built through a
new cssURL() helper that percent-encodes the characters that would
break it (space, quotes, parens, backslash). Stored cover paths are
already percent-encoded URL paths, so the escaping is defensive only.
This commit is contained in:
1 parent
807899b137
commit
ff17d14694
2 files changed
+121
-77
No files matched your search
@@ -5,10 +5,32 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
// NOTE: do not import "github.com/a-h/templ" here — templ's generator
|
||||
// already emits that import into the generated file, and a second copy
|
||||
// is a compile error (redeclared block).
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// cssURL neutralizes characters that would break an UNQUOTED CSS url()
|
||||
// token (whitespace, quotes, parens, backslash). The stored cover paths
|
||||
// are already percent-encoded URL paths, so this is defensive only — but
|
||||
// it must exist: templ's codegen HTML-escapes style attribute values a
|
||||
// second time, so ANY quote character (SafeCSS included) reaches the DOM
|
||||
// as literal ' text and the browser never parses the url() at all
|
||||
// (2026-10-21: every hero backdrop broken + /media/& 500 spam, because
|
||||
// Firefox resolved the mangled token relative to the page URL).
|
||||
func cssURL(s string) string {
|
||||
return strings.NewReplacer(
|
||||
" ", "%20",
|
||||
"(", "%28",
|
||||
")", "%29",
|
||||
"'", "%27",
|
||||
"\"", "%22",
|
||||
"\\", "%5C",
|
||||
).Replace(s)
|
||||
}
|
||||
|
||||
templ BookDetail(user User, book handlers.MediaDetail, errorMessage string, tombstoneDays int) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -33,7 +55,7 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string, tomb
|
||||
<!-- Hero with blurred cover backdrop -->
|
||||
<div class="relative overflow-hidden">
|
||||
if book.CoverImagePath.Valid && book.CoverImagePath.String != "" {
|
||||
<div class="hero-backdrop" style={ "background-image: url('" + book.CoverImagePath.String + "')" }></div>
|
||||
<div class="hero-backdrop" style={ templ.SafeCSS("background-image: url(" + cssURL(book.CoverImagePath.String) + ")") }></div>
|
||||
}
|
||||
<div class="relative z-10 xs:w-full md:mx-auto md:container px-4 sm:px-6 lg:px-8 pt-6 pb-8">
|
||||
<a id="back-link" href="/dashboard" class="inline-flex items-center gap-1.5 text-sm font-medium hover:underline transition-colors mb-6" style="color: var(--text-secondary);">
|
||||
|
||||
Reference in new issue
Block a user