Files
TermorServer/internal/httpapi/middleware.go
benya 35abd27473 feat: add sqlite-backed auth and library services
Bootstrap SQLite on server startup with embedded migrations and development seed data. Replace placeholder auth and library responses with database-backed services, bearer sessions, and repository-driven API handlers.
2026-04-02 22:22:38 +03:00

82 lines
2.0 KiB
Go

package httpapi
import (
"context"
"log"
"net/http"
"strings"
"time"
"github.com/benya/temporserv/internal/auth"
)
type contextKey string
const currentUserKey contextKey = "currentUser"
func requestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startedAt := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(startedAt))
})
}
func recoverer(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if recover() != nil {
http.Error(w, "internal server error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
func cors(origins string) func(http.Handler) http.Handler {
allowed := strings.Split(origins, ",")
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
for _, candidate := range allowed {
if strings.TrimSpace(candidate) == origin {
w.Header().Set("Access-Control-Allow-Origin", origin)
break
}
}
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
}
func (a app) requireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, err := a.auth.CurrentUser(r.Context(), r.Header.Get("Authorization"))
if err != nil {
writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "unauthorized"})
return
}
ctx := context.WithValue(r.Context(), currentUserKey, user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func currentUserFromContext(r *http.Request) auth.User {
user, ok := r.Context().Value(currentUserKey).(auth.User)
if !ok {
return auth.User{}
}
return user
}