forked from TrueCloudLab/frostfs-node
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
|
package object
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/nspcc-dev/neofs-api-go/acl"
|
||
|
"github.com/nspcc-dev/neofs-api-go/object"
|
||
|
libacl "github.com/nspcc-dev/neofs-node/lib/acl"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
serviceResponse interface {
|
||
|
SetEpoch(uint64)
|
||
|
}
|
||
|
|
||
|
responsePreparer interface {
|
||
|
prepareResponse(context.Context, serviceRequest, serviceResponse) error
|
||
|
}
|
||
|
|
||
|
epochResponsePreparer struct {
|
||
|
epochRecv EpochReceiver
|
||
|
}
|
||
|
)
|
||
|
|
||
|
type complexResponsePreparer struct {
|
||
|
items []responsePreparer
|
||
|
}
|
||
|
|
||
|
type aclResponsePreparer struct {
|
||
|
eaclSrc libacl.ExtendedACLSource
|
||
|
|
||
|
aclInfoReceiver aclInfoReceiver
|
||
|
|
||
|
reqActCalc requestActionCalculator
|
||
|
}
|
||
|
|
||
|
type headersFromObject struct {
|
||
|
obj *Object
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
_ responsePreparer = (*epochResponsePreparer)(nil)
|
||
|
)
|
||
|
|
||
|
func (s headersFromObject) getHeaders() (*Object, bool) {
|
||
|
return s.obj, true
|
||
|
}
|
||
|
|
||
|
func (s complexResponsePreparer) prepareResponse(ctx context.Context, req serviceRequest, resp serviceResponse) error {
|
||
|
for i := range s.items {
|
||
|
if err := s.items[i].prepareResponse(ctx, req, resp); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *epochResponsePreparer) prepareResponse(_ context.Context, req serviceRequest, resp serviceResponse) error {
|
||
|
resp.SetEpoch(s.epochRecv.Epoch())
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *aclResponsePreparer) prepareResponse(ctx context.Context, req serviceRequest, resp serviceResponse) error {
|
||
|
aclInfo, err := s.aclInfoReceiver.getACLInfo(ctx, req)
|
||
|
if err != nil {
|
||
|
return errAccessDenied
|
||
|
} else if !aclInfo.checkBearer && !aclInfo.checkExtended {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var obj *Object
|
||
|
|
||
|
switch r := resp.(type) {
|
||
|
case *object.GetResponse:
|
||
|
obj = r.GetObject()
|
||
|
case *object.HeadResponse:
|
||
|
obj = r.GetObject()
|
||
|
case interface {
|
||
|
GetObject() *Object
|
||
|
}:
|
||
|
obj = r.GetObject()
|
||
|
}
|
||
|
|
||
|
if obj == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// FIXME: do not check request headers.
|
||
|
// At this stage request is already validated, but action calculator will check it again.
|
||
|
p := requestActionParams{
|
||
|
eaclSrc: s.eaclSrc,
|
||
|
request: req,
|
||
|
objHdrSrc: headersFromObject{
|
||
|
obj: obj,
|
||
|
},
|
||
|
target: aclInfo.target,
|
||
|
}
|
||
|
|
||
|
if aclInfo.checkBearer {
|
||
|
p.eaclSrc = eaclFromBearer{
|
||
|
bearer: req.GetBearerToken(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if action := s.reqActCalc.calculateRequestAction(ctx, p); action != acl.ActionAllow {
|
||
|
return errAccessDenied
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func makeDeleteResponse() *object.DeleteResponse {
|
||
|
return new(object.DeleteResponse)
|
||
|
}
|
||
|
|
||
|
func makeRangeHashResponse(v []Hash) *GetRangeHashResponse {
|
||
|
return &GetRangeHashResponse{Hashes: v}
|
||
|
}
|
||
|
|
||
|
func makeRangeResponse(v []byte) *GetRangeResponse {
|
||
|
return &GetRangeResponse{Fragment: v}
|
||
|
}
|
||
|
|
||
|
func makeSearchResponse(v []Address) *object.SearchResponse {
|
||
|
return &object.SearchResponse{Addresses: v}
|
||
|
}
|
||
|
|
||
|
func makeHeadResponse(v *Object) *object.HeadResponse {
|
||
|
return &object.HeadResponse{Object: v}
|
||
|
}
|
||
|
|
||
|
func makePutResponse(v Address) *object.PutResponse {
|
||
|
return &object.PutResponse{Address: v}
|
||
|
}
|
||
|
|
||
|
func makeGetHeaderResponse(v *Object) *object.GetResponse {
|
||
|
return &object.GetResponse{R: &object.GetResponse_Object{Object: v}}
|
||
|
}
|
||
|
|
||
|
func makeGetChunkResponse(v []byte) *object.GetResponse {
|
||
|
return &object.GetResponse{R: &object.GetResponse_Chunk{Chunk: v}}
|
||
|
}
|