Forráskód Böngészése

Avoid extra HTTP request for fetching custom stylesheet

Use inline CSS with a nonce and move CSP headers to a meta tag.
Frédéric Guillot 5 éve
szülő
commit
dd3f496d06

+ 0 - 1
http/response/builder.go

@@ -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 {

+ 3 - 4
http/response/builder_test.go

@@ -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 {

+ 5 - 2
template/functions.go

@@ -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.

+ 6 - 1
template/templates/common/layout.html

@@ -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>

+ 0 - 13
ui/static_stylesheet.go

@@ -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)