mirror of
https://github.com/Noooste/garage-ui.git
synced 2026-07-26 07:48:13 +00:00
202 lines
7.0 KiB
Go
202 lines
7.0 KiB
Go
package routes
|
|
|
|
import (
|
|
"Noooste/garage-ui/internal/auth"
|
|
"Noooste/garage-ui/internal/config"
|
|
"Noooste/garage-ui/internal/handlers"
|
|
"Noooste/garage-ui/internal/middleware"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
|
|
// Swagger imports
|
|
_ "Noooste/garage-ui/docs"
|
|
|
|
"github.com/Noooste/swagger"
|
|
)
|
|
|
|
// SetupRoutes configures all API routes
|
|
func SetupRoutes(
|
|
app *fiber.App,
|
|
cfg *config.Config,
|
|
authService *auth.AuthService,
|
|
healthHandler *handlers.HealthHandler,
|
|
bucketHandler *handlers.BucketHandler,
|
|
objectHandler *handlers.ObjectHandler,
|
|
userHandler *handlers.UserHandler,
|
|
clusterHandler *handlers.ClusterHandler,
|
|
monitoringHandler *handlers.MonitoringHandler,
|
|
) {
|
|
// Apply CORS middleware globally
|
|
app.Use(middleware.CORSMiddleware(&cfg.CORS))
|
|
|
|
// Health check endpoint (no auth required)
|
|
app.Get("/health", healthHandler.Check)
|
|
app.Get("/api/v1/health", healthHandler.Check)
|
|
|
|
// Swagger documentation endpoint (no auth required)
|
|
app.Get("/docs/*", swagger.HandlerDefault)
|
|
|
|
// API v1 group
|
|
api := app.Group("/api/v1")
|
|
|
|
// Apply authentication middleware to all API routes
|
|
api.Use(middleware.AuthMiddleware(&cfg.Auth, authService))
|
|
|
|
// Bucket routes
|
|
buckets := api.Group("/buckets")
|
|
{
|
|
buckets.Get("/", bucketHandler.ListBuckets) // List all buckets
|
|
buckets.Post("/", bucketHandler.CreateBucket) // Create a new bucket
|
|
buckets.Get("/:name", bucketHandler.GetBucketInfo) // Get bucket info
|
|
buckets.Delete("/:name", bucketHandler.DeleteBucket) // Delete a bucket
|
|
buckets.Post("/:name/permissions", bucketHandler.GrantBucketPermission) // Grant bucket permissions
|
|
}
|
|
|
|
// Object routes
|
|
objects := api.Group("/buckets/:bucket/objects")
|
|
{
|
|
objects.Get("/", objectHandler.ListObjects) // List objects in bucket
|
|
objects.Post("/", objectHandler.UploadObject) // Upload object (multipart)
|
|
objects.Post("/upload-multiple", objectHandler.UploadMultipleObjects) // Upload multiple objects
|
|
objects.Post("/delete-multiple", objectHandler.DeleteMultipleObjects) // Delete multiple objects
|
|
objects.Get("/:key", objectHandler.GetObject) // Download object
|
|
objects.Put("/:key", objectHandler.UploadObjectStream) // Upload object (stream)
|
|
objects.Delete("/:key", objectHandler.DeleteObject) // Delete object
|
|
objects.Head("/:key", objectHandler.GetObjectMetadata) // Get object metadata
|
|
objects.Post("/:key/presign", objectHandler.GetPresignedURL) // Generate pre-signed URL
|
|
}
|
|
|
|
// User/Key management routes
|
|
users := api.Group("/users")
|
|
{
|
|
users.Get("/", userHandler.ListUsers) // List all users/keys
|
|
users.Post("/", userHandler.CreateUser) // Create new user/key
|
|
users.Get("/:access_key", userHandler.GetUser) // Get user info
|
|
users.Delete("/:access_key", userHandler.DeleteUser) // Delete user/key
|
|
users.Patch("/:access_key", userHandler.UpdateUserPermissions) // Update user permissions
|
|
}
|
|
|
|
// Cluster management routes
|
|
cluster := api.Group("/cluster")
|
|
{
|
|
cluster.Get("/health", clusterHandler.GetHealth) // Get cluster health
|
|
cluster.Get("/status", clusterHandler.GetStatus) // Get cluster status
|
|
cluster.Get("/statistics", clusterHandler.GetStatistics) // Get cluster statistics
|
|
cluster.Get("/nodes/:node_id", clusterHandler.GetNodeInfo) // Get node info
|
|
cluster.Get("/nodes/:node_id/statistics", clusterHandler.GetNodeStatistics) // Get node statistics
|
|
}
|
|
|
|
// Monitoring routes
|
|
monitoring := api.Group("/monitoring")
|
|
{
|
|
monitoring.Get("/metrics", monitoringHandler.GetMetrics) // Get Prometheus metrics
|
|
monitoring.Get("/admin-health", monitoringHandler.CheckAdminHealth) // Check Admin API health
|
|
monitoring.Get("/dashboard", monitoringHandler.GetDashboardMetrics) // Get dashboard metrics
|
|
}
|
|
|
|
// OIDC authentication routes (only if OIDC is enabled)
|
|
if cfg.Auth.Mode == "oidc" && cfg.Auth.OIDC.Enabled {
|
|
authRoutes := app.Group("/auth")
|
|
{
|
|
// Login endpoint - redirects to OIDC provider
|
|
authRoutes.Get("/login", func(c fiber.Ctx) error {
|
|
// Generate state token for CSRF protection
|
|
state := "random-state-token" // In production, use a secure random token
|
|
authURL, err := authService.GetAuthorizationURL(state)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": "Failed to generate login URL",
|
|
})
|
|
}
|
|
return c.Redirect().To(authURL)
|
|
})
|
|
|
|
// Callback endpoint - handles OIDC redirect after login
|
|
authRoutes.Get("/callback", func(c fiber.Ctx) error {
|
|
// Get authorization code from query
|
|
code := c.Query("code")
|
|
if code == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": "Authorization code is required",
|
|
})
|
|
}
|
|
|
|
// Exchange code for tokens
|
|
ctx := c.Context()
|
|
token, err := authService.ExchangeCode(ctx, code)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "Failed to exchange authorization code",
|
|
})
|
|
}
|
|
|
|
// Extract ID token from OAuth2 token
|
|
rawIDToken, ok := token.Extra("id_token").(string)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "No ID token in response",
|
|
})
|
|
}
|
|
|
|
// Verify ID token and get user info
|
|
userInfo, err := authService.VerifyIDToken(ctx, rawIDToken)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "Invalid ID token",
|
|
})
|
|
}
|
|
|
|
// In production, you should:
|
|
// 1. Create a session and store it in Redis/memory
|
|
// 2. Set a secure session cookie
|
|
// 3. Redirect to the frontend with the session
|
|
|
|
// For now, just set the ID token as a cookie (not recommended for production)
|
|
c.Cookie(&fiber.Cookie{
|
|
Name: cfg.Auth.OIDC.CookieName,
|
|
Value: rawIDToken,
|
|
MaxAge: cfg.Auth.OIDC.SessionMaxAge,
|
|
Secure: cfg.Auth.OIDC.CookieSecure,
|
|
HTTPOnly: cfg.Auth.OIDC.CookieHTTPOnly,
|
|
SameSite: cfg.Auth.OIDC.CookieSameSite,
|
|
})
|
|
|
|
return c.JSON(fiber.Map{
|
|
"success": true,
|
|
"user": userInfo,
|
|
})
|
|
})
|
|
|
|
// Logout endpoint
|
|
authRoutes.Post("/logout", func(c fiber.Ctx) error {
|
|
// Clear session cookie
|
|
c.Cookie(&fiber.Cookie{
|
|
Name: cfg.Auth.OIDC.CookieName,
|
|
Value: "",
|
|
MaxAge: -1,
|
|
})
|
|
|
|
return c.JSON(fiber.Map{
|
|
"success": true,
|
|
"message": "Logged out successfully",
|
|
})
|
|
})
|
|
|
|
// User info endpoint
|
|
authRoutes.Get("/me", middleware.AuthMiddleware(&cfg.Auth, authService), func(c fiber.Ctx) error {
|
|
userInfo := c.Locals("userInfo")
|
|
if userInfo == nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
|
"error": "Not authenticated",
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"success": true,
|
|
"user": userInfo,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|