mirror of
https://github.com/Noooste/garage-ui.git
synced 2026-09-03 10:48:20 +00:00
refactor: streamline object key handling and improve app name format
Signed-off-by: Noooste <83548733+Noooste@users.noreply.github.com>
This commit is contained in:
@@ -12,48 +12,11 @@ type GrantBucketPermissionRequest struct {
|
|||||||
Permissions BucketKeyPermission `json:"permissions" validate:"required"`
|
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
|
// CreateUserRequest represents a request to create a new user/key
|
||||||
type CreateUserRequest struct {
|
type CreateUserRequest struct {
|
||||||
Name string `json:"name,omitempty"`
|
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
|
// UpdateUserRequest represents a request to update user permissions
|
||||||
type UpdateUserRequest struct {
|
type UpdateUserRequest struct {
|
||||||
Status *string `json:"status,omitempty"` // "active" or "inactive"
|
Status *string `json:"status,omitempty"` // "active" or "inactive"
|
||||||
|
|||||||
@@ -138,13 +138,6 @@ type BucketPermission struct {
|
|||||||
Owner bool `json:"owner"`
|
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 {
|
type PresignedURLResponse struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
ExpiresIn int64 `json:"expires_in"` // in seconds
|
ExpiresIn int64 `json:"expires_in"` // in seconds
|
||||||
|
|||||||
@@ -72,64 +72,38 @@ func SetupRoutes(
|
|||||||
objects.Post("/delete-multiple", objectHandler.DeleteMultipleObjects) // Delete multiple objects
|
objects.Post("/delete-multiple", objectHandler.DeleteMultipleObjects) // Delete multiple objects
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object-specific routes with wildcard key parameter (supports paths with slashes)
|
// Fiber v3 does not auto-decode wildcard params; fall back to the raw
|
||||||
// These need to be registered on the main app with auth middleware applied
|
// 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 {
|
objectWildcardHandler := func(c fiber.Ctx) error {
|
||||||
// Get the full path from wildcard parameter
|
path := decodeObjectKey(c)
|
||||||
// Note: Fiber v3 does NOT automatically decode params, we need to do it manually
|
switch {
|
||||||
path := c.Params("*")
|
case strings.HasSuffix(path, "/metadata"):
|
||||||
|
c.Locals("objectKey", strings.TrimSuffix(path, "/metadata"))
|
||||||
// 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)
|
|
||||||
return objectHandler.GetObjectMetadata(c)
|
return objectHandler.GetObjectMetadata(c)
|
||||||
}
|
case strings.HasSuffix(path, "/presign"):
|
||||||
// Check if it's a presign request
|
c.Locals("objectKey", strings.TrimSuffix(path, "/presign"))
|
||||||
if strings.HasSuffix(decodedPath, "/presign") {
|
|
||||||
// Remove /presign suffix to get the actual key
|
|
||||||
key := strings.TrimSuffix(decodedPath, "/presign")
|
|
||||||
c.Locals("objectKey", key)
|
|
||||||
return objectHandler.GetPresignedURL(c)
|
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 {
|
objectDeleteHandler := func(c fiber.Ctx) error {
|
||||||
path := c.Params("*")
|
c.Locals("objectKey", decodeObjectKey(c))
|
||||||
|
|
||||||
// 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)
|
|
||||||
return objectHandler.DeleteObject(c)
|
return objectHandler.DeleteObject(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
objectHeadHandler := func(c fiber.Ctx) error {
|
objectHeadHandler := func(c fiber.Ctx) error {
|
||||||
path := c.Params("*")
|
c.Locals("objectKey", decodeObjectKey(c))
|
||||||
|
|
||||||
// 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)
|
|
||||||
return objectHandler.GetObjectMetadata(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
|
// Extract ID token from OAuth2 token
|
||||||
rawIDToken, ok := token.Extra("id_token").(string)
|
rawIDToken, ok := token.Extra("id_token").(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -253,10 +232,8 @@ func SetupRoutes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !authService.IsAdmin(userInfo) {
|
if !authService.IsAdmin(userInfo) {
|
||||||
if uiFromUserinfo, uiErr := authService.GetUserInfo(ctx, token); uiErr == nil {
|
if ui, err := authService.GetUserInfo(ctx, token); err == nil && len(ui.Roles) > 0 {
|
||||||
if len(uiFromUserinfo.Roles) > 0 {
|
userInfo.Roles = ui.Roles
|
||||||
userInfo.Roles = uiFromUserinfo.Roles
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !authService.IsAdmin(userInfo) {
|
if !authService.IsAdmin(userInfo) {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ func NewS3Service(cfg *config.GarageConfig, adminService *GarageAdminService) *S
|
|||||||
}
|
}
|
||||||
|
|
||||||
client, err := minio.New(cfg.Endpoint, &minio.Options{
|
client, err := minio.New(cfg.Endpoint, &minio.Options{
|
||||||
//Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
|
|
||||||
Secure: cfg.UseSSL,
|
Secure: cfg.UseSSL,
|
||||||
Region: cfg.Region,
|
Region: cfg.Region,
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -140,7 +140,7 @@ func main() {
|
|||||||
|
|
||||||
// Create Fiber app with configuration
|
// Create Fiber app with configuration
|
||||||
app := fiber.New(fiber.Config{
|
app := fiber.New(fiber.Config{
|
||||||
AppName: "Garage UI Backend v" + version,
|
AppName: "Garage UI Backend | Version: " + version,
|
||||||
BodyLimit: int(maxBodySize),
|
BodyLimit: int(maxBodySize),
|
||||||
ReadBufferSize: readBufferSize,
|
ReadBufferSize: readBufferSize,
|
||||||
WriteBufferSize: writeBufferSize,
|
WriteBufferSize: writeBufferSize,
|
||||||
|
|||||||
Reference in New Issue
Block a user