bb25ecbd15
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
249 lines
6.1 KiB
Go
249 lines
6.1 KiB
Go
package container
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
|
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
|
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
|
|
containerSDK "github.com/nspcc-dev/neofs-sdk-go/container"
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
|
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
|
)
|
|
|
|
type morphExecutor struct {
|
|
rdr Reader
|
|
wrt Writer
|
|
}
|
|
|
|
// Reader is an interface of read-only container storage.
|
|
type Reader interface {
|
|
containercore.Source
|
|
eacl.Source
|
|
|
|
// List returns a list of container identifiers belonging
|
|
// to the specified user of NeoFS system. Returns the identifiers
|
|
// of all NeoFS containers if pointer to owner identifier is nil.
|
|
List(*user.ID) ([]*cid.ID, error)
|
|
}
|
|
|
|
// Writer is an interface of container storage updater.
|
|
type Writer interface {
|
|
// Put stores specified container in the side chain.
|
|
Put(*containerSDK.Container) (*cid.ID, error)
|
|
// Delete removes specified container from the side chain.
|
|
Delete(containercore.RemovalWitness) error
|
|
// PutEACL updates extended ACL table of specified container in the side chain.
|
|
PutEACL(*eaclSDK.Table) error
|
|
}
|
|
|
|
// ErrInvalidContext is thrown by morph ServiceExecutor when provided session
|
|
// token does not contain expected container context.
|
|
var ErrInvalidContext = errors.New("session token does not contain container context")
|
|
|
|
func NewExecutor(rdr Reader, wrt Writer) containerSvc.ServiceExecutor {
|
|
return &morphExecutor{
|
|
rdr: rdr,
|
|
wrt: wrt,
|
|
}
|
|
}
|
|
|
|
func (s *morphExecutor) Put(ctx containerSvc.ContextWithToken, body *container.PutRequestBody) (*container.PutResponseBody, error) {
|
|
sigV2 := body.GetSignature()
|
|
if sigV2 == nil {
|
|
// TODO(@cthulhu-rider): #1387 use "const" error
|
|
return nil, errors.New("missing signature")
|
|
}
|
|
|
|
cnr := containerSDK.NewContainerFromV2(body.GetContainer())
|
|
|
|
var sig neofscrypto.Signature
|
|
sig.ReadFromV2(*sigV2)
|
|
|
|
cnr.SetSignature(&sig)
|
|
|
|
tok := session.NewTokenFromV2(ctx.SessionToken)
|
|
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
|
return nil, ErrInvalidContext
|
|
}
|
|
|
|
cnr.SetSessionToken(tok)
|
|
|
|
idCnr, err := s.wrt.Put(cnr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var idCnrV2 refs.ContainerID
|
|
idCnr.WriteToV2(&idCnrV2)
|
|
|
|
res := new(container.PutResponseBody)
|
|
res.SetContainerID(&idCnrV2)
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *morphExecutor) Delete(ctx containerSvc.ContextWithToken, body *container.DeleteRequestBody) (*container.DeleteResponseBody, error) {
|
|
idV2 := body.GetContainerID()
|
|
if idV2 == nil {
|
|
return nil, errors.New("missing container ID")
|
|
}
|
|
|
|
var id cid.ID
|
|
|
|
err := id.ReadFromV2(*idV2)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid container ID: %w", err)
|
|
}
|
|
|
|
sig := body.GetSignature().GetSign()
|
|
|
|
tok := session.NewTokenFromV2(ctx.SessionToken)
|
|
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
|
return nil, ErrInvalidContext
|
|
}
|
|
|
|
var rmWitness containercore.RemovalWitness
|
|
|
|
rmWitness.SetContainerID(&id)
|
|
rmWitness.SetSignature(sig)
|
|
rmWitness.SetSessionToken(tok)
|
|
|
|
err = s.wrt.Delete(rmWitness)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return new(container.DeleteResponseBody), nil
|
|
}
|
|
|
|
func (s *morphExecutor) Get(ctx context.Context, body *container.GetRequestBody) (*container.GetResponseBody, error) {
|
|
idV2 := body.GetContainerID()
|
|
if idV2 == nil {
|
|
return nil, errors.New("missing container ID")
|
|
}
|
|
|
|
var id cid.ID
|
|
|
|
err := id.ReadFromV2(*idV2)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid container ID: %w", err)
|
|
}
|
|
|
|
cnr, err := s.rdr.Get(&id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var sigV2 *refs.Signature
|
|
|
|
if sig := cnr.Signature(); sig != nil {
|
|
sigV2 = new(refs.Signature)
|
|
sig.WriteToV2(sigV2)
|
|
}
|
|
|
|
res := new(container.GetResponseBody)
|
|
res.SetContainer(cnr.ToV2())
|
|
res.SetSignature(sigV2)
|
|
res.SetSessionToken(cnr.SessionToken().ToV2())
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *morphExecutor) List(ctx context.Context, body *container.ListRequestBody) (*container.ListResponseBody, error) {
|
|
idV2 := body.GetOwnerID()
|
|
if idV2 == nil {
|
|
return nil, fmt.Errorf("missing user ID")
|
|
}
|
|
|
|
var id user.ID
|
|
|
|
err := id.ReadFromV2(*idV2)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid user ID: %w", err)
|
|
}
|
|
|
|
cnrs, err := s.rdr.List(&id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cidList := make([]refs.ContainerID, len(cnrs))
|
|
for i := range cnrs {
|
|
cnrs[i].WriteToV2(&cidList[i])
|
|
}
|
|
|
|
res := new(container.ListResponseBody)
|
|
res.SetContainerIDs(cidList)
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *morphExecutor) SetExtendedACL(ctx containerSvc.ContextWithToken, body *container.SetExtendedACLRequestBody) (*container.SetExtendedACLResponseBody, error) {
|
|
sigV2 := body.GetSignature()
|
|
if sigV2 == nil {
|
|
// TODO(@cthulhu-rider): #1387 use "const" error
|
|
return nil, errors.New("missing signature")
|
|
}
|
|
|
|
table := eaclSDK.NewTableFromV2(body.GetEACL())
|
|
|
|
var sig neofscrypto.Signature
|
|
sig.ReadFromV2(*sigV2)
|
|
|
|
table.SetSignature(&sig)
|
|
|
|
tok := session.NewTokenFromV2(ctx.SessionToken)
|
|
if ctx.SessionToken != nil && session.GetContainerContext(tok) == nil {
|
|
return nil, ErrInvalidContext
|
|
}
|
|
|
|
table.SetSessionToken(tok)
|
|
|
|
err := s.wrt.PutEACL(table)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return new(container.SetExtendedACLResponseBody), nil
|
|
}
|
|
|
|
func (s *morphExecutor) GetExtendedACL(ctx context.Context, body *container.GetExtendedACLRequestBody) (*container.GetExtendedACLResponseBody, error) {
|
|
idV2 := body.GetContainerID()
|
|
if idV2 == nil {
|
|
return nil, errors.New("missing container ID")
|
|
}
|
|
|
|
var id cid.ID
|
|
|
|
err := id.ReadFromV2(*idV2)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid container ID: %w", err)
|
|
}
|
|
|
|
table, err := s.rdr.GetEACL(&id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var sigV2 *refs.Signature
|
|
|
|
if sig := table.Signature(); sig != nil {
|
|
sigV2 = new(refs.Signature)
|
|
sig.WriteToV2(sigV2)
|
|
}
|
|
|
|
res := new(container.GetExtendedACLResponseBody)
|
|
res.SetEACL(table.ToV2())
|
|
res.SetSignature(sigV2)
|
|
res.SetSessionToken(table.SessionToken().ToV2())
|
|
|
|
return res, nil
|
|
}
|