package middleware import ( "log/slog" "net/http" "orbits-server/internal/server/api/assets" "orbits-server/internal/server/service" "strings" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" ) const authPrefix = "Bearer" func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc { // Make a slog-looking logger, inspired by the gin docs themself // JSON logger: https://gin-gonic.com/en/docs/logging/structured-logging/ return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() logger.Debug("request", slog.String("method", c.Request.Method), slog.String("path", path), slog.String("query", query), slog.Int("status", c.Writer.Status()), slog.Duration("latency", time.Since(start)), slog.String("client_ip", c.ClientIP()), slog.Int("body_size", c.Writer.Size()), ) if len(c.Errors) > 0 { for _, err := range c.Errors { logger.Error("request error", slog.String("error", err.Error())) } } } } func AuthMiddleware(db *gorm.DB) gin.HandlerFunc { keyService := service.NewKeyService(db) return func(c *gin.Context) { header := c.GetHeader("Authorization") if len(header) == 0 { c.AbortWithStatusJSON(http.StatusUnauthorized, assets.ResponseObject{ Msg: "Authorization header is required", }) return } if !strings.HasPrefix(header, authPrefix) { c.AbortWithStatusJSON(http.StatusUnauthorized, assets.ResponseObject{ Msg: "Invalid authorization header", }) return } token := strings.TrimSpace(header[len(authPrefix):]) ok := keyService.Validate(token) if !ok { c.AbortWithStatusJSON(http.StatusUnauthorized, assets.ResponseObject{ Msg: "Invalid key", }) return } c.Next() } }