package middleware import ( "time" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" ) func Logger() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path raw := c.Request.URL.RawQuery c.Next() latency := time.Since(start) clientIP := c.ClientIP() method := c.Request.Method statusCode := c.Writer.Status() bodySize := c.Writer.Size() if raw != "" { path = path + "?" + raw } log.Info(). Str("method", method). Str("path", path). Int("status", statusCode). Dur("latency", latency). Str("client_ip", clientIP). Int("body_size", bodySize). Msg("HTTP request") } } func Recovery() gin.HandlerFunc { return gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { log.Error(). Interface("error", recovered). Str("path", c.Request.URL.Path). Msg("Panic recovered") c.JSON(500, gin.H{ "success": false, "error": gin.H{ "code": "INTERNAL_ERROR", "message": "Internal server error", }, }) c.Abort() }) } func CORS(allowedOrigins []string) gin.HandlerFunc { return func(c *gin.Context) { origin := c.Request.Header.Get("Origin") allowed := false for _, o := range allowedOrigins { if o == "*" || o == origin { allowed = true break } } if allowed { c.Writer.Header().Set("Access-Control-Allow-Origin", origin) } c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH, DELETE") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } func SecurityHeaders() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("X-Content-Type-Options", "nosniff") c.Writer.Header().Set("X-Frame-Options", "DENY") c.Writer.Header().Set("X-XSS-Protection", "1; mode=block") c.Writer.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") c.Writer.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'") c.Next() } } func RateLimiter(requests int, window time.Duration) gin.HandlerFunc { return func(c *gin.Context) { c.Next() } }