From bd35a5ece14b4fd3710f72c46ea11c2b43fd7edb Mon Sep 17 00:00:00 2001 From: jpedro-cf Date: Fri, 7 Nov 2025 16:19:11 -0300 Subject: [PATCH] feat: added bucket cors requests using aws sdk --- backend/router/buckets.go | 92 +++++++++++++++++++++++++++++++++++++++ backend/router/router.go | 2 + backend/schema/bucket.go | 8 ++++ backend/utils/utils.go | 7 +++ 4 files changed, 109 insertions(+) diff --git a/backend/router/buckets.go b/backend/router/buckets.go index bbd92b2..b1c105a 100644 --- a/backend/router/buckets.go +++ b/backend/router/buckets.go @@ -1,11 +1,16 @@ package router import ( + "context" "encoding/json" "fmt" "khairul169/garage-webui/schema" "khairul169/garage-webui/utils" "net/http" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" ) type Buckets struct{} @@ -52,3 +57,90 @@ func (b *Buckets) GetAll(w http.ResponseWriter, r *http.Request) { utils.ResponseSuccess(w, res) } + +func (b*Buckets) GetCors(w http.ResponseWriter, r *http.Request){ + bucket := r.PathValue("bucket") + + client, err := getS3Client(bucket) + + if err != nil { + utils.ResponseError(w, err) + return + } + + out, err := client.GetBucketCors(context.Background(), &s3.GetBucketCorsInput{ + Bucket: aws.String(bucket), + }) + + res := []schema.BucketCors{} + + for _, rule := range out.CORSRules { + res = append(res, schema.BucketCors{ + AllowedOrigins: rule.AllowedOrigins, + AllowedMethods: rule.AllowedMethods, + AllowedHeaders: rule.AllowedHeaders, + ExposeHeaders: rule.ExposeHeaders, + MaxAgeSeconds: rule.MaxAgeSeconds, + }) + } + + if err != nil { + utils.ResponseError(w, err) + return + } + + utils.ResponseSuccess(w, res) +} + +func (b*Buckets) PutCors(w http.ResponseWriter, r *http.Request){ + bucket := r.PathValue("bucket") + + + var body struct { + Rules []schema.BucketCors `json:"rules"` + } + + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + utils.ResponseError(w, err) + return + } + + client, err := getS3Client(bucket) + + if err != nil { + utils.ResponseError(w, err) + return + } + + cors := make([]types.CORSRule, 0, len(body.Rules)) + + for _, rule := range body.Rules { + if len(rule.AllowedMethods) == 0 || len(rule.AllowedOrigins) == 0 { + utils.ResponseError(w, fmt.Errorf("each CORS rule must have at least one allowed method and origin")) + return + } + + cors = append(cors, types.CORSRule{ + AllowedHeaders: utils.NilIfEmpty(rule.AllowedHeaders), + AllowedMethods: rule.AllowedMethods, // required + AllowedOrigins: rule.AllowedOrigins, // required + ExposeHeaders: utils.NilIfEmpty(rule.ExposeHeaders), + MaxAgeSeconds: rule.MaxAgeSeconds, + }) +} + + res, err := client.PutBucketCors(context.Background(), &s3.PutBucketCorsInput{ + Bucket: aws.String(bucket), + CORSConfiguration: &types.CORSConfiguration{ + CORSRules: cors, + }, + }) + + if err != nil { + utils.ResponseError(w, err) + return + } + + utils.ResponseSuccess(w, res) +} + diff --git a/backend/router/router.go b/backend/router/router.go index 1cf3134..4275d93 100644 --- a/backend/router/router.go +++ b/backend/router/router.go @@ -20,6 +20,8 @@ func HandleApiRouter() *http.ServeMux { buckets := &Buckets{} router.HandleFunc("GET /buckets", buckets.GetAll) + router.HandleFunc("GET /buckets/{bucket}/cors", buckets.GetCors) + router.HandleFunc("PUT /buckets/{bucket}/cors", buckets.PutCors) browse := &Browse{} router.HandleFunc("GET /browse/{bucket}", browse.GetObjects) diff --git a/backend/schema/bucket.go b/backend/schema/bucket.go index c809dec..e721d66 100644 --- a/backend/schema/bucket.go +++ b/backend/schema/bucket.go @@ -24,6 +24,14 @@ type Bucket struct { Created string `json:"created"` } +type BucketCors struct { + AllowedOrigins []string `json:"allowedOrigins"` + AllowedMethods []string `json:"allowedMethods"` + AllowedHeaders []string `json:"allowedHeaders"` + ExposeHeaders []string `json:"exposeHeaders"` + MaxAgeSeconds *int32 `json:"maxAgeSeconds"` +} + type LocalAlias struct { AccessKeyID string `json:"accessKeyId"` Alias string `json:"alias"` diff --git a/backend/utils/utils.go b/backend/utils/utils.go index 30c6c6d..30a3b8c 100644 --- a/backend/utils/utils.go +++ b/backend/utils/utils.go @@ -18,6 +18,13 @@ func LastString(str []string) string { return str[len(str)-1] } +func NilIfEmpty[T any](s []T) []T { + if len(s) == 0 { + return nil + } + return s +} + func ResponseError(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error()))