package fuphttp import ( "crypto/subtle" "fmt" "net/http" "github.com/gorilla/mux" ) func tokenFromRequest(r *http.Request) (token string, ok bool) { // Check for a Fup-Token header. v := r.Header.Get("Fup-Token") if v != "" { return v, true } // Check for basic auth. _, v, ok = r.BasicAuth() return v, ok } func TokenAuthMiddleware(token, realm string) mux.MiddlewareFunc { return func(next http.Handler) http.Handler { if token == "" { return next } tokenBytes := []byte(token) return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() if !IsMutate(ctx) { // Allow all access to public pages. next.ServeHTTP(rw, r) return } requestAuth := func(s string) { rw.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q, charset=\"UTF-8\"", realm)) http.Error(rw, s, http.StatusUnauthorized) } pw, ok := tokenFromRequest(r) switch { case !ok: requestAuth("unparsable or no credentials") return case subtle.ConstantTimeCompare([]byte(pw), tokenBytes) != 1: requestAuth("bad credentials") return } // Auth check passed, let's go. next.ServeHTTP(rw, r) return }) } }