129 lines
3.3 KiB
Go
129 lines
3.3 KiB
Go
|
|
package middleware
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"web-qudo-be/app/database/entity"
|
||
|
|
|
||
|
|
"github.com/gofiber/fiber/v2"
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
ClientKeyHeader = "X-Client-Key"
|
||
|
|
ClientContextKey = "client_id"
|
||
|
|
)
|
||
|
|
|
||
|
|
// excludedPaths contains paths that don't require client key validation
|
||
|
|
var excludedPaths = []string{
|
||
|
|
"/swagger/*",
|
||
|
|
"/docs/*",
|
||
|
|
"/users/login",
|
||
|
|
"/health/*",
|
||
|
|
"/clients",
|
||
|
|
"/clients/*",
|
||
|
|
"*/viewer/*",
|
||
|
|
"/bookmarks/test-table",
|
||
|
|
}
|
||
|
|
|
||
|
|
// isPathExcluded checks if the given path should be excluded from client key validation
|
||
|
|
func isPathExcluded(path string) bool {
|
||
|
|
for _, excludedPath := range excludedPaths {
|
||
|
|
if strings.HasPrefix(excludedPath, "*") && strings.HasSuffix(excludedPath, "*") {
|
||
|
|
// Handle wildcard at both beginning and end (e.g., "*/viewer/*")
|
||
|
|
pattern := excludedPath[1 : len(excludedPath)-1] // Remove * from both ends
|
||
|
|
if strings.Contains(path, pattern) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
} else if strings.HasPrefix(excludedPath, "*") {
|
||
|
|
// Handle wildcard at the beginning
|
||
|
|
if strings.HasSuffix(path, excludedPath[1:]) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
} else if strings.HasSuffix(excludedPath, "*") {
|
||
|
|
// Handle wildcard at the end
|
||
|
|
prefix := excludedPath[:len(excludedPath)-1]
|
||
|
|
if strings.HasPrefix(path, prefix) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// Exact match
|
||
|
|
if path == excludedPath {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// ClientMiddleware extracts and validates the Client Key from request headers
|
||
|
|
func ClientMiddleware(db *gorm.DB) fiber.Handler {
|
||
|
|
return func(c *fiber.Ctx) error {
|
||
|
|
// Check if path should be excluded from client key validation
|
||
|
|
if isPathExcluded(c.Path()) {
|
||
|
|
return c.Next()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Extract Client Key from header
|
||
|
|
clientKey := c.Get(ClientKeyHeader)
|
||
|
|
|
||
|
|
if clientKey == "" {
|
||
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
|
|
"success": false,
|
||
|
|
"code": 400,
|
||
|
|
"messages": []string{"Client Key is required in header: " + ClientKeyHeader},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Parse UUID
|
||
|
|
clientUUID, err := uuid.Parse(clientKey)
|
||
|
|
if err != nil {
|
||
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
|
|
"success": false,
|
||
|
|
"code": 400,
|
||
|
|
"messages": []string{"Invalid Client Key format"},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Validate client exists and is active
|
||
|
|
var client entity.Clients
|
||
|
|
if err := db.Where("id = ? AND is_active = ?", clientUUID, true).First(&client).Error; err != nil {
|
||
|
|
if err == gorm.ErrRecordNotFound {
|
||
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||
|
|
"success": false,
|
||
|
|
"code": 401,
|
||
|
|
"messages": []string{"Invalid or inactive Client Key"},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
|
|
"success": false,
|
||
|
|
"code": 500,
|
||
|
|
"messages": []string{"Error validating Client Key"},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Store client ID in context for use in handlers
|
||
|
|
c.Locals(ClientContextKey, clientUUID)
|
||
|
|
|
||
|
|
return c.Next()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetClientID retrieves the client ID from the context
|
||
|
|
func GetClientID(c *fiber.Ctx) *uuid.UUID {
|
||
|
|
if clientID, ok := c.Locals(ClientContextKey).(uuid.UUID); ok {
|
||
|
|
return &clientID
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// AddExcludedPath adds a new path to the excluded paths list
|
||
|
|
func AddExcludedPath(path string) {
|
||
|
|
excludedPaths = append(excludedPaths, path)
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetExcludedPaths returns the current list of excluded paths
|
||
|
|
func GetExcludedPaths() []string {
|
||
|
|
return excludedPaths
|
||
|
|
}
|