M main.go => main.go +0 -5
@@ 19,11 19,6 @@ type application struct {
errLog *log.Logger
templates map[string]*template.Template
- // In order to use inline css, we need to set a randomly generated nonce
- // value for each request. This is set in our secureHeaders middleware
- // and then used in our base template.
- cspNonce string
-
lists *models.ListModel
}
M middleaware.go => middleaware.go +13 -1
@@ 1,6 1,7 @@
package main
import (
+ "context"
"crypto/rand"
"encoding/base64"
"fmt"
@@ 14,6 15,9 @@ func cspNonce() (string, error) {
return base64.RawStdEncoding.EncodeToString(b), err
}
+// secureHeaders is a middleware which adds strict CSP and other headers.
+// A CSP nonce is stored in the request's context which can be retrieved with
+// the nonce helper function.
func (app *application) secureHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nonce, err := cspNonce()
@@ 31,12 35,20 @@ func (app *application) secureHeaders(next http.Handler) http.Handler {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "deny")
w.Header().Set("X-XSS-Protection", "0")
- app.cspNonce = nonce
+ r = r.WithContext(context.WithValue(r.Context(), "nonce", nonce))
next.ServeHTTP(w, r)
})
}
+// nonce retrieves a stored nonce string from a request's context.
+func nonce(c context.Context) string {
+ if val, ok := c.Value("nonce").(string); ok {
+ return val
+ }
+ return ""
+}
+
// logRequest is a middleware that prints each request to the info log.
func (app *application) logRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
M routes.go => routes.go +2 -2
@@ 53,7 53,7 @@ func (app *application) render(
// home handles displaying the home page.
func (app *application) home(w http.ResponseWriter, r *http.Request) {
app.render(w, http.StatusOK, "home.tmpl", homePage{
- CSPNonce: app.cspNonce,
+ CSPNonce: nonce(r.Context()),
})
}
@@ 108,7 108,7 @@ func (app *application) view(w http.ResponseWriter, r *http.Request) {
}
app.render(w, http.StatusOK, "list.tmpl", viewPage{
- CSPNonce: app.cspNonce,
+ CSPNonce: nonce(r.Context()),
Name: list.Name,
Body: list.Body,
})