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:
parent
09be3d2bac
commit
dd3f496d06
5 changed files with 14 additions and 21 deletions
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue