Avoid extra HTTP request for fetching custom stylesheet

Use inline CSS with a nonce and move CSP headers to a meta tag.
This commit is contained in:
Frédéric Guillot 2021-05-31 14:16:50 -07:00 committed by fguillot
parent 09be3d2bac
commit dd3f496d06
5 changed files with 14 additions and 21 deletions

View File

@ -96,7 +96,6 @@ func (b *Builder) writeHeaders() {
b.headers["X-XSS-Protection"] = "1; mode=block"
b.headers["X-Content-Type-Options"] = "nosniff"
b.headers["X-Frame-Options"] = "DENY"
b.headers["Content-Security-Policy"] = "default-src 'self'; img-src * data:; media-src *; frame-src *"
b.headers["Referrer-Policy"] = "no-referrer"
for key, value := range b.headers {

View File

@ -29,10 +29,9 @@ func TestResponseHasCommonHeaders(t *testing.T) {
resp := w.Result()
headers := map[string]string{
"X-XSS-Protection": "1; mode=block",
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Content-Security-Policy": "default-src 'self'; img-src * data:; media-src *; frame-src *",
"X-XSS-Protection": "1; mode=block",
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
}
for header, expected := range headers {

View File

@ -51,6 +51,9 @@ func (f *funcMap) Map() template.FuncMap {
"safeURL": func(url string) template.URL {
return template.URL(url)
},
"safeCSS": func(str string) template.CSS {
return template.CSS(str)
},
"noescape": func(str string) template.HTML {
return template.HTML(str)
},
@ -91,8 +94,8 @@ func (f *funcMap) Map() template.FuncMap {
iconName,
))
},
"rand": func() string {
return crypto.GenerateRandomStringHex(10)
"nonce": func() string {
return crypto.GenerateRandomStringHex(16)
},
// These functions are overrode at runtime after the parsing.

View File

@ -31,8 +31,13 @@
<meta name="theme-color" content="{{ theme_color .theme }}">
<link rel="stylesheet" type="text/css" href="{{ route "stylesheet" "name" .theme }}?{{ .theme_checksum }}">
{{ if and .user .user.Stylesheet }}
<link rel="stylesheet" type="text/css" href="{{ route "stylesheet" "name" "custom_css" }}?{{ rand }}">
{{ $stylesheetNonce := nonce }}
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; style-src 'nonce-{{ $stylesheetNonce }}'">
<style nonce="{{ $stylesheetNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
{{ else }}
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *">
{{ end }}
<script src="{{ route "javascript" "name" "app" }}?{{ .app_js_checksum }}" defer></script>

View File

@ -16,19 +16,6 @@ import (
func (h *handler) showStylesheet(w http.ResponseWriter, r *http.Request) {
filename := request.RouteStringParam(r, "name")
if filename == "custom_css" {
user, err := h.store.UserByID(request.UserID(r))
if err != nil || user == nil {
html.NotFound(w, r)
return
}
b := response.New(w, r)
b.WithHeader("Content-Type", "text/css; charset=utf-8")
b.WithBody(user.Stylesheet)
b.Write()
return
}
etag, found := static.StylesheetBundleChecksums[filename]
if !found {
html.NotFound(w, r)