From 740acadd3793659b834767b993f090ba712561df Mon Sep 17 00:00:00 2001
From: Denis Kirillov <d.kirillov@yadro.com>
Date: Mon, 20 Feb 2023 12:18:29 +0300
Subject: [PATCH] [TrueCloudLab#36] Fix cors object payload

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
---
 api/handler/cors_test.go | 41 ++++++++++++++++++++++++++++++++++++++++
 api/layer/cors.go        |  2 +-
 api/layer/neofs_mock.go  | 21 +++++++++++++++++++-
 api/layer/tree_mock.go   | 25 ++++++++++++++++++++++--
 4 files changed, 85 insertions(+), 4 deletions(-)
 create mode 100644 api/handler/cors_test.go

diff --git a/api/handler/cors_test.go b/api/handler/cors_test.go
new file mode 100644
index 00000000..bbd0edf9
--- /dev/null
+++ b/api/handler/cors_test.go
@@ -0,0 +1,41 @@
+package handler
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"testing"
+
+	"github.com/TrueCloudLab/frostfs-s3-gw/api"
+)
+
+func TestCORSOriginWildcard(t *testing.T) {
+	body := `
+<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+	<CORSRule>
+		<AllowedMethod>GET</AllowedMethod>
+		<AllowedOrigin>*</AllowedOrigin>
+	</CORSRule>
+</CORSConfiguration>
+`
+	hc := prepareHandlerContext(t)
+
+	bktName := "bucket-for-cors"
+	box, _ := createAccessBox(t)
+	w, r := prepareTestRequest(hc, bktName, "", nil)
+	ctx := context.WithValue(r.Context(), api.BoxData, box)
+	r = r.WithContext(ctx)
+	r.Header.Add(api.AmzACL, "public-read")
+	hc.Handler().CreateBucketHandler(w, r)
+	assertStatus(t, w, http.StatusOK)
+
+	w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
+	ctx = context.WithValue(r.Context(), api.BoxData, box)
+	r = r.WithContext(ctx)
+	hc.Handler().PutBucketCorsHandler(w, r)
+	assertStatus(t, w, http.StatusOK)
+
+	w, r = prepareTestPayloadRequest(hc, bktName, "", nil)
+	hc.Handler().GetBucketCorsHandler(w, r)
+	assertStatus(t, w, http.StatusOK)
+}
diff --git a/api/layer/cors.go b/api/layer/cors.go
index baaac62a..bef3393e 100644
--- a/api/layer/cors.go
+++ b/api/layer/cors.go
@@ -39,7 +39,7 @@ func (n *layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
 	prm := PrmObjectCreate{
 		Container:    p.BktInfo.CID,
 		Creator:      p.BktInfo.Owner,
-		Payload:      p.Reader,
+		Payload:      &buf,
 		Filepath:     p.BktInfo.CORSObjectName(),
 		CreationTime: TimeNow(ctx),
 		CopiesNumber: p.CopiesNumber,
diff --git a/api/layer/neofs_mock.go b/api/layer/neofs_mock.go
index af6a2597..112caf83 100644
--- a/api/layer/neofs_mock.go
+++ b/api/layer/neofs_mock.go
@@ -144,7 +144,7 @@ func (t *TestFrostFS) ReadObject(ctx context.Context, prm PrmObjectRead) (*Objec
 
 	if obj, ok := t.objects[sAddr]; ok {
 		owner := getOwner(ctx)
-		if !obj.OwnerID().Equals(owner) {
+		if !obj.OwnerID().Equals(owner) && !t.isPublicRead(prm.Container) {
 			return nil, ErrAccessDenied
 		}
 
@@ -282,6 +282,25 @@ func (t *TestFrostFS) ContainerEACL(_ context.Context, cnrID cid.ID) (*eacl.Tabl
 	return table, nil
 }
 
+func (t *TestFrostFS) isPublicRead(cnrID cid.ID) bool {
+	table, ok := t.eaclTables[cnrID.EncodeToString()]
+	if !ok {
+		return false
+	}
+
+	for _, rec := range table.Records() {
+		if rec.Operation() == eacl.OperationGet && len(rec.Filters()) == 0 {
+			for _, trgt := range rec.Targets() {
+				if trgt.Role() == eacl.RoleOthers {
+					return rec.Action() == eacl.ActionAllow
+				}
+			}
+		}
+	}
+
+	return false
+}
+
 func getOwner(ctx context.Context) user.ID {
 	if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil && bd.Gate.BearerToken != nil {
 		return bearer.ResolveIssuer(*bd.Gate.BearerToken)
diff --git a/api/layer/tree_mock.go b/api/layer/tree_mock.go
index de4c60b7..790735fe 100644
--- a/api/layer/tree_mock.go
+++ b/api/layer/tree_mock.go
@@ -109,11 +109,32 @@ func (t *TreeServiceMock) PutNotificationConfigurationNode(ctx context.Context,
 }
 
 func (t *TreeServiceMock) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {
-	panic("implement me")
+	systemMap, ok := t.system[bktInfo.CID.EncodeToString()]
+	if !ok {
+		return oid.ID{}, nil
+	}
+
+	node, ok := systemMap["cors"]
+	if !ok {
+		return oid.ID{}, nil
+	}
+
+	return node.OID, nil
 }
 
 func (t *TreeServiceMock) PutBucketCORS(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID) (oid.ID, error) {
-	panic("implement me")
+	systemMap, ok := t.system[bktInfo.CID.EncodeToString()]
+	if !ok {
+		systemMap = make(map[string]*data.BaseNodeVersion)
+	}
+
+	systemMap["cors"] = &data.BaseNodeVersion{
+		OID: objID,
+	}
+
+	t.system[bktInfo.CID.EncodeToString()] = systemMap
+
+	return oid.ID{}, ErrNoNodeToRemove
 }
 
 func (t *TreeServiceMock) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (oid.ID, error) {