~kota/lists

bef63af106a5dbe4a6efa124e3a2af893228a696 — Dakota Walsh 7 months ago f7932a0
fix csp nonce race condition
3 files changed, 15 insertions(+), 8 deletions(-)

M main.go
M middleaware.go
M routes.go
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,
	})