154 lines
3.7 KiB
Go
154 lines
3.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"fmt"
|
|
"sno/internal/service"
|
|
"sno/internal/types"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// AdminConfig holds configuration for admin middleware
|
|
type AdminConfig struct {
|
|
AdminService service.AdminService
|
|
}
|
|
|
|
// RequireRole middleware to check user roles
|
|
func RequireRole(roles ...types.UserRole) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
// Skip role checking for OPTIONS preflight requests
|
|
if c.Method() == "OPTIONS" {
|
|
return c.Next()
|
|
}
|
|
|
|
userData := GetTelegramUser(c)
|
|
if userData == nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"success": false,
|
|
"message": "User not authenticated",
|
|
})
|
|
}
|
|
|
|
// Check if user has any of the required roles
|
|
userRole, err := getUserRole(c, userData.ID)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"success": false,
|
|
"message": "Failed to verify user role",
|
|
})
|
|
}
|
|
|
|
for _, role := range roles {
|
|
if userRole == role {
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
|
"success": false,
|
|
"message": fmt.Sprintf("Insufficient permissions. Required role: one of %v", roles),
|
|
})
|
|
}
|
|
}
|
|
|
|
// RequireAdmin middleware to check if user is admin
|
|
func RequireAdmin(config AdminConfig) fiber.Handler {
|
|
return RequireRole(types.RoleAdmin)
|
|
}
|
|
|
|
// RequireOperator middleware to check if user is operator or admin
|
|
func RequireOperator(config AdminConfig) fiber.Handler {
|
|
return RequireRole(types.RoleAdmin, types.RoleOperator)
|
|
}
|
|
|
|
// getUserRole retrieves user role from database or cache
|
|
func getUserRole(c *fiber.Ctx, userID int64) (types.UserRole, error) {
|
|
// For now, we'll check if user exists in admins table
|
|
// In production, you might want to cache this in Redis
|
|
|
|
// Try to get from context first (cached)
|
|
if role, ok := c.Locals("user_role").(types.UserRole); ok {
|
|
return role, nil
|
|
}
|
|
|
|
// Get admin service from context
|
|
adminService, ok := c.Locals("admin_service").(service.AdminService)
|
|
if !ok {
|
|
// Fallback: if no admin service, assume user role
|
|
return types.RoleUser, nil
|
|
}
|
|
|
|
// Check if user is admin
|
|
role, err := adminService.GetUserRole(c.Context(), userID)
|
|
if err != nil {
|
|
// If user not found in admins table, they are regular user
|
|
return types.RoleUser, nil
|
|
}
|
|
|
|
// Cache role in context
|
|
c.Locals("user_role", role)
|
|
|
|
return role, nil
|
|
}
|
|
|
|
// AdminMiddleware middleware for admin routes
|
|
func AdminMiddleware(config AdminConfig) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
// Store admin service in context for role checking
|
|
c.Locals("admin_service", config.AdminService)
|
|
|
|
// Apply auth middleware first
|
|
return AuthMiddleware(AuthConfig{})(c)
|
|
}
|
|
}
|
|
|
|
// WithAdminRoles applies both admin middleware and role checking
|
|
func WithAdminRoles(config AdminConfig, roles ...types.UserRole) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
// First, apply admin middleware (includes auth)
|
|
if err := AdminMiddleware(config)(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Then check roles
|
|
return RequireRole(roles...)(c)
|
|
}
|
|
}
|
|
|
|
// Convenience functions
|
|
func IsAdmin(c *fiber.Ctx) bool {
|
|
userData := GetTelegramUser(c)
|
|
if userData == nil {
|
|
return false
|
|
}
|
|
|
|
role, err := getUserRole(c, userData.ID)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return role == types.RoleAdmin
|
|
}
|
|
|
|
func IsOperator(c *fiber.Ctx) bool {
|
|
userData := GetTelegramUser(c)
|
|
if userData == nil {
|
|
return false
|
|
}
|
|
|
|
role, err := getUserRole(c, userData.ID)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return role == types.RoleOperator || role == types.RoleAdmin
|
|
}
|
|
|
|
func GetCurrentUserRole(c *fiber.Ctx) (types.UserRole, error) {
|
|
userData := GetTelegramUser(c)
|
|
if userData == nil {
|
|
return "", fmt.Errorf("user not authenticated")
|
|
}
|
|
|
|
return getUserRole(c, userData.ID)
|
|
} |