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 }