package middleware import ( "net/http" "smoop-api/internal/handlers" "smoop-api/internal/models" "strconv" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" ) // DeviceAccessFilter middleware sets filtering context for device access func DeviceAccessFilter() gin.HandlerFunc { return func(c *gin.Context) { userContext, exists := c.Get("user") if !exists { c.JSON(401, gin.H{"error": "unauthorized"}) c.Abort() return } user, ok := userContext.(handlers.UserContext) if !ok { c.JSON(401, gin.H{"error": "invalid user data"}) c.Abort() return } // Set filter flag and user ID in context if user.Role == models.RoleAdmin { c.Set("filterDevices", false) // Admin sees all devices } else { c.Set("filterDevices", true) // Regular user needs filtering c.Set("userID", user.ID) // Store user ID for filtering } c.Next() } } // TrackerAccessFilter middleware sets filtering context for tracker access func TrackerAccessFilter() gin.HandlerFunc { return func(c *gin.Context) { userContext, exists := c.Get("user") if !exists { c.JSON(401, gin.H{"error": "unauthorized"}) c.Abort() return } user, ok := userContext.(handlers.UserContext) if !ok { c.JSON(401, gin.H{"error": "invalid user data"}) c.Abort() return } // Set filter flag and user ID in context (mirrors devices) if user.Role == models.RoleAdmin { c.Set("filterTrackers", false) // Admin sees all trackers } else { c.Set("filterTrackers", true) // Regular user needs filtering c.Set("userID", user.ID) // Store user ID for filtering (same key as devices) } c.Next() } } // UserSelfOrAdmin allows access to /users/:id for admins or the user itself. // Works whether context has only "claims" (router.Auth) or both "user" and "claims" (handlers.Auth). func UserSelfOrAdmin() gin.HandlerFunc { return func(c *gin.Context) { idStr := c.Param("id") targetID, _ := strconv.Atoi(idStr) if targetID <= 0 { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid id"}) return } // 1) Prefer JWT claims (compatible with router.Auth) if v, ok := c.Get("claims"); ok { if m, ok := v.(jwt.MapClaims); ok { role, _ := m["role"].(string) uid := 0 switch t := m["sub"].(type) { case float64: uid = int(t) case int: uid = t case int64: uid = int(t) } if role == "admin" || uid == targetID { c.Next() return } } } // 2) Fallback to user context (compatible with handlers.Auth) if v, ok := c.Get("user"); ok { if u, ok := v.(handlers.UserContext); ok { if u.Role == models.RoleAdmin || int(u.ID) == targetID { c.Next() return } } } c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "forbidden"}) } }