diff --git a/backend/internal/models/requests.go b/backend/internal/models/requests.go index 87f8eb5..73ee721 100644 --- a/backend/internal/models/requests.go +++ b/backend/internal/models/requests.go @@ -12,48 +12,11 @@ type GrantBucketPermissionRequest struct { Permissions BucketKeyPermission `json:"permissions" validate:"required"` } -// DeleteBucketRequest represents a request to delete a bucket -type DeleteBucketRequest struct { - Name string `json:"name" validate:"required"` -} - -// ListObjectsRequest represents a request to list objects in a bucket -type ListObjectsRequest struct { - Bucket string `json:"bucket" validate:"required"` - Prefix string `json:"prefix,omitempty"` - MaxKeys int `json:"max_keys,omitempty"` - Marker string `json:"marker,omitempty"` -} - -// UploadObjectRequest represents metadata for an object upload -type UploadObjectRequest struct { - Bucket string `json:"bucket" validate:"required"` - Key string `json:"key" validate:"required"` - ContentType string `json:"content_type,omitempty"` -} - -// DeleteObjectRequest represents a request to delete an object -type DeleteObjectRequest struct { - Bucket string `json:"bucket" validate:"required"` - Key string `json:"key" validate:"required"` -} - -// GetObjectRequest represents a request to get/download an object -type GetObjectRequest struct { - Bucket string `json:"bucket" validate:"required"` - Key string `json:"key" validate:"required"` -} - // CreateUserRequest represents a request to create a new user/key type CreateUserRequest struct { Name string `json:"name,omitempty"` } -// DeleteUserRequest represents a request to delete a user/key -type DeleteUserRequest struct { - AccessKey string `json:"access_key" validate:"required"` -} - // UpdateUserRequest represents a request to update user permissions type UpdateUserRequest struct { Status *string `json:"status,omitempty"` // "active" or "inactive" diff --git a/backend/internal/models/responses.go b/backend/internal/models/responses.go index aac5851..f6afeda 100644 --- a/backend/internal/models/responses.go +++ b/backend/internal/models/responses.go @@ -138,13 +138,6 @@ type BucketPermission struct { Owner bool `json:"owner"` } -// Permission represents a permission entry for access control (legacy/deprecated) -type Permission struct { - Resource string `json:"resource"` - Actions []string `json:"actions"` - Effect string `json:"effect"` // "Allow" or "Deny" -} - type PresignedURLResponse struct { URL string `json:"url"` ExpiresIn int64 `json:"expires_in"` // in seconds diff --git a/backend/internal/routes/routes.go b/backend/internal/routes/routes.go index 59358f2..67b1a96 100644 --- a/backend/internal/routes/routes.go +++ b/backend/internal/routes/routes.go @@ -72,64 +72,38 @@ func SetupRoutes( objects.Post("/delete-multiple", objectHandler.DeleteMultipleObjects) // Delete multiple objects } - // Object-specific routes with wildcard key parameter (supports paths with slashes) - // These need to be registered on the main app with auth middleware applied + // Fiber v3 does not auto-decode wildcard params; fall back to the raw + // value when QueryUnescape fails. + decodeObjectKey := func(c fiber.Ctx) string { + raw := c.Params("*") + if decoded, err := url.QueryUnescape(raw); err == nil { + return decoded + } + return raw + } + objectWildcardHandler := func(c fiber.Ctx) error { - // Get the full path from wildcard parameter - // Note: Fiber v3 does NOT automatically decode params, we need to do it manually - path := c.Params("*") - - // Decode the full path using QueryUnescape (handles %20, %2F, etc.) - decodedPath, err := url.QueryUnescape(path) - if err != nil { - // If decoding fails, use the original path - decodedPath = path - } - - // Check if it's a metadata request - if strings.HasSuffix(decodedPath, "/metadata") { - // Remove /metadata suffix to get the actual key - key := strings.TrimSuffix(decodedPath, "/metadata") - c.Locals("objectKey", key) + path := decodeObjectKey(c) + switch { + case strings.HasSuffix(path, "/metadata"): + c.Locals("objectKey", strings.TrimSuffix(path, "/metadata")) return objectHandler.GetObjectMetadata(c) - } - // Check if it's a presign request - if strings.HasSuffix(decodedPath, "/presign") { - // Remove /presign suffix to get the actual key - key := strings.TrimSuffix(decodedPath, "/presign") - c.Locals("objectKey", key) + case strings.HasSuffix(path, "/presign"): + c.Locals("objectKey", strings.TrimSuffix(path, "/presign")) return objectHandler.GetPresignedURL(c) + default: + c.Locals("objectKey", path) + return objectHandler.GetObject(c) } - // Otherwise, it's a regular object download - c.Locals("objectKey", decodedPath) - return objectHandler.GetObject(c) } objectDeleteHandler := func(c fiber.Ctx) error { - path := c.Params("*") - - // Decode the full path using QueryUnescape - key, err := url.QueryUnescape(path) - if err != nil { - // If decoding fails, use the original path - key = path - } - - c.Locals("objectKey", key) + c.Locals("objectKey", decodeObjectKey(c)) return objectHandler.DeleteObject(c) } objectHeadHandler := func(c fiber.Ctx) error { - path := c.Params("*") - - // Decode the full path using QueryUnescape - key, err := url.QueryUnescape(path) - if err != nil { - // If decoding fails, use the original path - key = path - } - - c.Locals("objectKey", key) + c.Locals("objectKey", decodeObjectKey(c)) return objectHandler.GetObjectMetadata(c) } @@ -226,6 +200,11 @@ func SetupRoutes( }) } + logger.Debug(). + Str("access_token", token.AccessToken). + Interface("token", token). + Msg("Exchanged authorization code for token") + // Extract ID token from OAuth2 token rawIDToken, ok := token.Extra("id_token").(string) if !ok { @@ -253,10 +232,8 @@ func SetupRoutes( } } if !authService.IsAdmin(userInfo) { - if uiFromUserinfo, uiErr := authService.GetUserInfo(ctx, token); uiErr == nil { - if len(uiFromUserinfo.Roles) > 0 { - userInfo.Roles = uiFromUserinfo.Roles - } + if ui, err := authService.GetUserInfo(ctx, token); err == nil && len(ui.Roles) > 0 { + userInfo.Roles = ui.Roles } } if !authService.IsAdmin(userInfo) { diff --git a/backend/internal/services/s3.go b/backend/internal/services/s3.go index 925bac9..db51829 100644 --- a/backend/internal/services/s3.go +++ b/backend/internal/services/s3.go @@ -37,7 +37,6 @@ func NewS3Service(cfg *config.GarageConfig, adminService *GarageAdminService) *S } client, err := minio.New(cfg.Endpoint, &minio.Options{ - //Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""), Secure: cfg.UseSSL, Region: cfg.Region, }) diff --git a/backend/main.go b/backend/main.go index 300270f..177473c 100644 --- a/backend/main.go +++ b/backend/main.go @@ -140,7 +140,7 @@ func main() { // Create Fiber app with configuration app := fiber.New(fiber.Config{ - AppName: "Garage UI Backend v" + version, + AppName: "Garage UI Backend | Version: " + version, BodyLimit: int(maxBodySize), ReadBufferSize: readBufferSize, WriteBufferSize: writeBufferSize,