box/internal/app/middleware.go
2026-05-15 17:40:09 +02:00

85 lines
2.2 KiB
Go

package app
import (
"context"
"log"
"net/http"
"strings"
"time"
)
type ctxKey string
const userKey ctxKey = "user"
func (a *App) withAuth(next func(http.ResponseWriter, *http.Request, User)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var u User
if a.cfg.DevMode {
u = User{Username: a.cfg.DemoUser, Email: a.cfg.DemoEmail}
} else {
u = User{Username: r.Header.Get(a.cfg.AuthHeaderUser), Email: r.Header.Get(a.cfg.AuthHeaderEmail)}
if u.Username == "" {
http.Error(w, "missing authenticated user header", http.StatusUnauthorized)
return
}
}
next(w, r.WithContext(context.WithValue(r.Context(), userKey, u)), u)
}
}
func (a *App) withAPIUser(next func(http.ResponseWriter, *http.Request, User)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if a.cfg.DevMode {
u := User{Username: a.cfg.DemoUser, Email: a.cfg.DemoEmail}
next(w, r.WithContext(context.WithValue(r.Context(), userKey, u)), u)
return
}
authz := strings.TrimSpace(r.Header.Get("Authorization"))
if !strings.HasPrefix(strings.ToLower(authz), "bearer ") {
http.Error(w, "missing bearer token", http.StatusUnauthorized)
return
}
token := strings.TrimSpace(authz[len("Bearer "):])
u, err := a.validateBearerToken(token)
if err != nil {
http.Error(w, "invalid bearer token", http.StatusUnauthorized)
return
}
next(w, r.WithContext(context.WithValue(r.Context(), userKey, u)), u)
}
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
lrw := &logResponseWriter{ResponseWriter: w, status: http.StatusOK}
next.ServeHTTP(lrw, r)
log.Printf("method=%s path=%s status=%d bytes=%d dur_ms=%d remote=%s ua=%q",
r.Method,
r.URL.Path,
lrw.status,
lrw.bytes,
time.Since(start).Milliseconds(),
r.RemoteAddr,
r.UserAgent(),
)
})
}
type logResponseWriter struct {
http.ResponseWriter
status int
bytes int
}
func (l *logResponseWriter) WriteHeader(statusCode int) {
l.status = statusCode
l.ResponseWriter.WriteHeader(statusCode)
}
func (l *logResponseWriter) Write(b []byte) (int, error) {
n, err := l.ResponseWriter.Write(b)
l.bytes += n
return n, err
}