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-XSS-Protection"] = "1; mode=block"
|
||||||
b.headers["X-Content-Type-Options"] = "nosniff"
|
b.headers["X-Content-Type-Options"] = "nosniff"
|
||||||
b.headers["X-Frame-Options"] = "DENY"
|
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"
|
b.headers["Referrer-Policy"] = "no-referrer"
|
||||||
|
|
||||||
for key, value := range b.headers {
|
for key, value := range b.headers {
|
||||||
|
|
|
@ -29,10 +29,9 @@ func TestResponseHasCommonHeaders(t *testing.T) {
|
||||||
resp := w.Result()
|
resp := w.Result()
|
||||||
|
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"X-XSS-Protection": "1; mode=block",
|
"X-XSS-Protection": "1; mode=block",
|
||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
"X-Frame-Options": "DENY",
|
"X-Frame-Options": "DENY",
|
||||||
"Content-Security-Policy": "default-src 'self'; img-src * data:; media-src *; frame-src *",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for header, expected := range headers {
|
for header, expected := range headers {
|
||||||
|
|
|
@ -51,6 +51,9 @@ func (f *funcMap) Map() template.FuncMap {
|
||||||
"safeURL": func(url string) template.URL {
|
"safeURL": func(url string) template.URL {
|
||||||
return template.URL(url)
|
return template.URL(url)
|
||||||
},
|
},
|
||||||
|
"safeCSS": func(str string) template.CSS {
|
||||||
|
return template.CSS(str)
|
||||||
|
},
|
||||||
"noescape": func(str string) template.HTML {
|
"noescape": func(str string) template.HTML {
|
||||||
return template.HTML(str)
|
return template.HTML(str)
|
||||||
},
|
},
|
||||||
|
@ -91,8 +94,8 @@ func (f *funcMap) Map() template.FuncMap {
|
||||||
iconName,
|
iconName,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
"rand": func() string {
|
"nonce": func() string {
|
||||||
return crypto.GenerateRandomStringHex(10)
|
return crypto.GenerateRandomStringHex(16)
|
||||||
},
|
},
|
||||||
|
|
||||||
// These functions are overrode at runtime after the parsing.
|
// These functions are overrode at runtime after the parsing.
|
||||||
|
|
|
@ -31,8 +31,13 @@
|
||||||
|
|
||||||
<meta name="theme-color" content="{{ theme_color .theme }}">
|
<meta name="theme-color" content="{{ theme_color .theme }}">
|
||||||
<link rel="stylesheet" type="text/css" href="{{ route "stylesheet" "name" .theme }}?{{ .theme_checksum }}">
|
<link rel="stylesheet" type="text/css" href="{{ route "stylesheet" "name" .theme }}?{{ .theme_checksum }}">
|
||||||
|
|
||||||
{{ if and .user .user.Stylesheet }}
|
{{ 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 }}
|
{{ end }}
|
||||||
|
|
||||||
<script src="{{ route "javascript" "name" "app" }}?{{ .app_js_checksum }}" defer></script>
|
<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) {
|
func (h *handler) showStylesheet(w http.ResponseWriter, r *http.Request) {
|
||||||
filename := request.RouteStringParam(r, "name")
|
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]
|
etag, found := static.StylesheetBundleChecksums[filename]
|
||||||
if !found {
|
if !found {
|
||||||
html.NotFound(w, r)
|
html.NotFound(w, r)
|
||||||
|
|
Loading…
Reference in a new issue