// backend/middleware.go package main import ( "net/http" "strings" "time" "github.com/tus/tusd/pkg/handler" "scm.bstein.dev/bstein/Pegasus/backend/internal" ) type loggingRW struct { http.ResponseWriter status int } func (l *loggingRW) WriteHeader(code int) { l.status = code l.ResponseWriter.WriteHeader(code) } func sessionRequired(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := internal.CurrentUser(r); err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } next.ServeHTTP(w, r) }) } func corsForTus(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if origin := r.Header.Get("Origin"); origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Vary", "Origin") } w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Methods", "GET,POST,HEAD,PATCH,DELETE,OPTIONS") w.Header().Set("Access-Control-Max-Age", "86400") w.Header().Set( "Access-Control-Allow-Headers", "Content-Type, Tus-Resumable, Upload-Length, Upload-Defer-Length, Upload-Metadata, Upload-Offset, Upload-Concat, Upload-Checksum, X-Requested-With", ) w.Header().Set("Access-Control-Expose-Headers", "Location, Upload-Offset, Upload-Length, Tus-Resumable, Upload-Checksum") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next.ServeHTTP(w, r) }) } func claimsFromHook(ev handler.HookEvent) (internal.Claims, error) { req := ev.HTTPRequest if req.Header == nil { return internal.Claims{}, http.ErrNoCookie } r := http.Request{Header: http.Header(req.Header)} return internal.CurrentUser(&r) } func redactHeaders(h http.Header) http.Header { cp := http.Header{} for k, v := range h { kk := strings.ToLower(k) if kk == "cookie" || strings.HasPrefix(kk, "authorization") || strings.Contains(kk, "token") { cp[k] = []string{""} continue } cp[k] = append([]string(nil), v...) } return cp } func debugHandler(next http.Handler) http.Handler { if !internal.Debug { return next } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { id := time.Now().UnixNano() internal.Logf(">> %d %s %s %v", id, req.Method, req.URL.Path, redactHeaders(req.Header)) rw := &loggingRW{ResponseWriter: w, status: http.StatusOK} start := time.Now() next.ServeHTTP(rw, req) internal.Logf("<< %d %s %s %d %s", id, req.Method, req.URL.Path, rw.status, time.Since(start)) }) }